:-dynamic(errorLexico/0).


/*
	NOTA DE EJECUCIÓN:
			compilador(Fichero .cod)
	
	Se generará un fichero de salida 'out.obj' en caso de que la compilación haya sido satisfactoria
*/




% NOTA INICIAL: Para hacer mas facil a la vista las operaciones lógicas, escribo las operaciones aquí
and([],true):-!.
and([false|_],false):-!.
and([true|Xs],Sol):-!,and(Xs,Sol).

or([],false):-!.
or([true|_],true):-!.
or([false|Xs],Sol):-!,or(Xs,Sol).

not(false,true):-!.
not(true,false):-!.

igual(X,X,true):-!.
igual(_,_,false):-!.

distinto(X,X,false):-!.
distinto(_,_,true):-!.

mayor(V1,V2,true):-V1 > V2,!.
mayor(_,_,false):-!.


agrega([],[]).
agrega([[]|Xs],Ys):-!,agrega(Xs,Ys).
agrega([[X]|Xs],[X|Ys]):-!,agrega(Xs,Ys).
agrega([[X|Xs]|Xs1],[X|Ys]):-!,agrega([Xs|Xs1],Ys).
%maximo(+Val1,+Val2,-Max)
maximo(X,Y,X):-X > Y,!.
maximo(_,Y,Y):-!.

% anhadeID(+TSinicial,+ident,+clase,+dir,+propiedades,-TSresultado)
anhadeID([],ID,Clase,Dir,Props,[[(id,ID),(clase,Clase),(dir,Dir),(props,Props)]]):-!.
anhadeID([X|Xs],Id,Clase,Dir,Props,[X|Ys]):-!,anhadeID(Xs,Id,Clase,Dir,Props,Ys).

%existeID(+TS,+Objetivo,-Resultado)
existeID([],_,false):-!.
existeID([[(id,X)|_]|_],X,true):-!.
existeID([[(id,_)|_]|Ys],X,Res):-!,existeID(Ys,X,Res).
existeID([[(_,_)|Xs]|Ys],X,Res):-!,existeID([Xs|Ys],X,Res).

%dameAtrib(+Props,+Atrib,-Valor).
dameAtrib([(Atrib,Valor)|_],Atrib,Valor):-!.
dameAtrib([(_,_)|Xs],Atrib,Valor):-!,dameAtrib(Xs,Atrib,Valor).

%agregaPropiedad(+ListaPropiedades,+Clave,+Atributp,-ListaResultado)
agregaPropiedad([],X,Y,[(X,Y)]):-!.
agregaPropiedad([X|Xs],Y,Z,[X|Res]):-!,agregaPropiedad(Xs,Y,Z,Res).

%atribCampo(+Propiedades,+Atributo,-Valor).
atribCampo([],_,_):-!,write('AVISO: Campo sin identificador. Revisar implem.'),flush,abort.
atribCampo([(Atr,X)|_],Atr,X):-!.
atribCampo([(_,_)|Xs],X,Res):-!,atribCampo(Xs,X,Res).

%existeCampos(+TS,+Objetivo,-Resultado)
existeCampo(Campos,ID,Res):-existeID(Campos,ID,Res),!.


dameCampo(Campos,ID,Res):-existeCampo(Campos,ID,true),!,buscaEnTabla(Campos,ID,Res). %TODO: Chequear. No me fio de los formatos

%idCampo(Campo,ID,IDCampo),
atrCampo(CampoCampo,Atr,Res):-dameAtrib(CampoCampo,Atr,Res),!.

%pertenece(+Elemento,+Lista) <--- Funcion solo usada para operacion de union. Equiv. a "member", pero esa da problemas por temas de atomicidad
pertenece(X,[X|_]):-!.
pertenece(X,[_|Ys]):-!,pertenece(X,Ys).

%Union(+Lista1,+Lista2,-ListaRes)
union([],Ys,Ys):-!.
union([X|Xs],Ys,Zs):-pertenece(X,Ys),!,union(Xs,Ys,Zs).
union([X|Xs],Ys,[X|Zs]):-!,union(Xs,Ys,Zs).

%Quita(+Elemento a eliminar,+Lista,-Lista Resultado)
quita([],Xs,Xs):-!.
quita(_,[],[]):-!.
quita(X,[X|Xs],Xs):-!.
quita(X,[Y|Xs],[Y|Zs]):-!,quita(X,Xs,Zs).

%buscaEnTabla(+TS,+ID,-TS[ID])
buscaEnTabla([],_,_):-!.
buscaEnTabla([Ent|_],ID,Ent):-dameAtrib(Ent,id,ID),!.
buscaEnTabla([_|Xs],ID,Ent):-!,buscaEnTabla(Xs,ID,Ent).

%creaTS(+TablaPadre,-TablaHijo)
creaTS(Ts,Ts).

/* Funciones necesarias para el compilador */
longInicio(4).
atrInicio(NumNiveles,TamDatos,[apila_i(NumNiveles1),desapila_dir(1),apila_i(Aux),desapila_dir(0)]):-Aux is 1+NumNiveles+TamDatos,
																									NumNiveles1 is NumNiveles + 1.

longInicioPaso(3).
inicioPaso([]).

longFinPaso(1).
finPaso([]).
/*
longAccesoVar(pvar,4):-!.
longAccesoVar(_,3):-!.
*/
%ref(+TS,+Props,-Propsres)
ref(TS,ID,IDRes):-buscaEnTabla(TS,ID,E),dameAtrib(E,props,Props),dameAtrib(Props,t,ref),!,dameAtrib(Props,id,ID1),ref(TS,ID1,IDRes).
ref(_,ID,ID):-!.

comprobarAlias(X,X).

%compatibles(TS,Tipo1,Tipo2,true). %TODO
compatibles(_,_,_,true).

longAccesoVar(_,1).
accesoVar(TS,ID,Cod):-existeID(TS,ID,true),!,buscaEnTabla(TS,ID,E),dameAtrib(E,dir,Dir),Cod=[apila_dir(Dir)].	%TODO
%-------------------------------------------------------------------------------

%Prog(-ErrProg,-CodProg)
prog(ErrProg,CodProg) --> 
		{
		/*
			Decs.tsh = creaTS()
			Decs.nh = 0
			Decs.dirh = 0
			Decs.pendsh = {}		
			
			Decs.etqh = LongInicio() + 1 
		*/

			creaTS(TshDecs,[]),
			NhDecs is 1,
			DirhDecs is 0,
			PendshDecs = [],
			
			longInicio(LongInicio),
			EtqhDecs is LongInicio + 2
		},
		decs(TshDecs,DirhDecs,NhDecs,NDecs,PendshDecs,PendsDecs,TsDecs,DirDecs,ErrDecs,EtqhDecs,EtqDecs,CodDecs),
		{
		/*
			Acts.ts = comprobarAlias(Decs.ts)
			Acts.nh = 0
			TODO: comprobarAlias(Decs.ts)
			
			Acts.reth = error
			
			Acts.etqh = Decs.etq
		*/			
			RethActs = error,
			comprobarAlias(TsDecs,TsActs),
			NhActs is 0
		},
		acts(TsActs,NhActs,RethActs,ErrActs,EtqDecs,_,CodActs),
		{
		/*
			Progs.err = Decs.err v Acts.err v Decs.pends != { }
							
			Prog.cod = Inicio() || "Ir_a(Decs.etq)" || Decs.cod || Acts.cod
		*/			
			distinto(PendsDecs,[],Sol),
			or([ErrDecs,ErrActs,Sol],ErrProg),
			
			atrInicio(NDecs,DirDecs,Inicio),
			
			agrega([Inicio,[ir_a(EtqDecs)],CodDecs,CodActs],CodProg)
		}.
		
%Decs(+Tsh,+Dirh,+Nh,-N,+Pendsh,-Pends,-TS,-Dir,-ErrDecs,+Etqh,-Etq,-Cod)
decs(TshDecs,DirhDecs,NhDecs,NDecs,PendshDecs,PendsDecs,TSDecs,DirDecs,ErrDecs,EtqhDecs,EtqDecs,CodDecs)-->
/*
	Dec.tsh = Decs.tsh
	Dec.dirh = Decs.dirh
	Dec.nh = Decs.nh
	
	Dec.etqh = Decs.etqh
*/ 
	dec(TshDecs,DirhDecs,NhDecs,NDec,PendsDec,IDDec,ClaseDec,DirDec,PropsDec,ErrDec,EtqhDecs,EtqDec,CodDec),
	{		
	/*
		RDecs.tsh = añadeID(Decs.tsh, Dec.id, Dec.clase, Dec.dir, Dec.props)
		RDecs.dirh = Dec.dir
		RDecs.nh = Decs.nh
		RDecs.pendsh = Decs.pendsh
		
		RDecs.etqh = Dec.etq
	*/		
		anhadeID(TshDecs,IDDec,ClaseDec,DirDec,PropsDec,TshRDecs)
	},
	rDecs(TshRDecs,DirDec,NhDecs,NRDecs,PendshDecs,PendsRDecs,TSDecs,DirDecs,ErrRDecs,EtqDec,EtqDecs,CodRDecs),
	{
	/*	
		Decs.ts = RDecs.ts
		Decs.dir = RDecs.dir
		Decs.n = max ( Dec.n, RDecs.n)
		Decs.pends = RDecs.pends U Dec.pends - (if(Dec.clase == Tipo, {Dec.id}, {}))
		
		Decs.err = RDecs.err v Dec.err v (existeID(RDecs.ts, Dec.id) && RDecs.ts[Dec.id].props.nivel == Decs.nh)
		
		Decs.etq = RDecs.etq
		Decs.cod = Dec.cod || RDecs.cod
	*/			
		union(PendsRDecs,PendsDec,Pends1),		
		existeID(TSDecs,IDDec,ExisteID),
		buscaEnTabla(TSDecs,IDDec,E),
		dameAtrib(E,props,Props),
		dameAtrib(Props,nivel,NivelDecID),
		igual(NivelDecID,NhDecs,IgualNivel),
		and([ExisteID,IgualNivel],Sol1),
		or([ErrRDecs,ErrDec,Sol1],ErrDecs),		
		agrega([CodDec,CodRDecs],CodDecs),		
		maximo(NDec,NRDecs,NDecs),
		(igual(ClaseDec,tipo,true) -> 
			quita(Pends1,[IDDec],PendsDecs)
			; 
			quita(Pends1,[],PendsDecs)
		),		
		maximo(NDec,NRDecs,NDecs)
	}.

%RDecs(+Tsh,+Dirh,+Nh,-N,+Pendsh,-Pends,-TS,-Dir,-ErrRDecs,+Etqh,-Etq,-Cod)
rDecs(TshRDecs0,DirhRDecs0,NhRDecs0,NRDecs0,PendshRDecs0,PendsRDecs0,TSRDecs0,DirRDecs0,ErrRDecs0,EtqhRDecs0,EtqRDecs0,CodRDecs0) --> 
	/*
		Dec.tsh = RDecs(0).tsh
		Dec.dirh = RDecs(0).dirh
		Dec.nh = RDecs(0).nh
		
		Dec.etqh = RDecs(0).etqh
	*/	
	dec(TshRDecs0,DirhRDecs0,NhRDecs0,NDec,PendsDec,IDDec,ClaseDec,DirDec,PropsDec,ErrDec,EtqhRDecs0,EtqDec,CodDec),
	{
	/*
		RDecs(1).tsh = anhadeID(RDecs(0).tsh, Dec.id, Dec.clase, Dec.dir, Dec.props)
		RDecs(1).dirh = Dec.dir
		RDecs(1).nh = RDecs(0).nh
		RDecs(1).pendsh = RDecs(0).pendsh
		
		RDecs(1).etqh = Dec.etq	
	*/
		anhadeID(TshRDecs0,IDDec,ClaseDec,DirDec,PropsDec,TshRDecs1)
	},
	rDecs(TshRDecs1,DirDec,NhRDecs0,NRDecs1,PendshRDecs0,PendsRDecs1,TSRDecs0,DirRDecs0,ErrRDecs1,EtqDec,EtqRDecs0,CodRDecs1),	
	{	
	/*
		RDecs(0).ts = RDecs(1).ts
		RDecs(0).dir = RDecs(1).dir
		RDecs(0).n = max ( Dec.n, RDecs(1).n)
		TODO RDecs(0).pends = RDecs(1).pends U Dec.pends - (if(Dec.clase == Tipo, {Dec.id}, {}))
		
		RDecs(0).err = RDecs(1).err v Dec.err v (existeID(RDecs(1).ts, Dec.id) && RDecs(1).ts[Dec.id].props.nivel == RDecs(0).nh)
		
		RDecs(0).etq = RDecs(1).etq
		RDecs(0).cod = Dec.cod || RDecs(1).cod
	*/		
		union(PendsRDecs1,PendsDec,Pends1),		
		existeID(TSRDecs0,IDDec,ExisteID),
		buscaEnTabla(TSRDecs0,IDDec,E),
		dameAtrib(E,props,Props),
		dameAtrib(Props,nivel,NivelDecID),
		igual(NivelDecID,NhRDecs0,IgualNivel),
		and([ExisteID,IgualNivel],Sol1),
		or([ErrRDecs1,ErrDec,Sol1],ErrRDecs0),
		agrega([CodDec,CodRDecs1],CodRDecs0),				
%TODO POSIBLE PIFIA DE LOS PARENTESIS AQUI
		(igual(ClaseDec,tipo,true)-> 
			quita(Pends1,[IDDec],PendsRDecs0) 
			; 
			quita(Pends1,[],PendsRDecs0)
		),
		maximo(NDec,NRDecs1,NRDecs0)
		}.

%RDecs(+Tsh,+Dirh,+Nh,-N,+Pendsh,-Pends,-TS,-Dir,+Etqh,-Etq,-Cod)
rDecs(TshRDecs,DirhRDecs,NhRDecs,NhRDecs,PendshRDecs,PendshRDecs,TshRDecs,DirhRDecs,ErrRDecs,EtqhRDecs,EtqhRDecs,CodRDecs) --> 
/*
	lambda
*/
	[],
/*
		RDecs.ts= RDecs.tsh
		RDecs.n = RDecs.nh
		RDecs.dir = RDecs.dirh
		RDecs.pends = RDecs.pendsh
		
		RDecs.err = False
		
		RDecs.etq = RDecs.etqh
		RDecs.cod = ""	
*/
	{
		ErrRDecs = false,
		CodRDecs = []
	}.

%Dec(+Tsh,+Dirh,+Nh,-N,-Pends,-ID,-Clase,-Dir,-Props,-Error,+Etqh,-Etq,-Cod)
dec(TshDec,DirhDec,NhDec,NhDec,PendsDec,IDDec,ClaseDec,DirDec,PropsDec,ErrDec,EtqhDec,EtqDec,CodDec) --> 
/*
		DecVar.tsh = Dec.tsh
		
		DecVar.etqh = Dec.etqh
*/
	decVar(TshDec, _, PendsDec, IDDec, ClaseDec, PropsDecVar,ErrDec,EtqhDec,EtqDec,CodDec),
	{
		agregaPropiedad(PropsDecVar,nivel,NhDec,PropsDec),
		dameAtrib(PropsDecVar,tam,PropsTamDecVar),
		DirDec is DirhDec + PropsTamDecVar		
/*	
		Dec.pends = DecVar.pends
		Dec.id = DecVar.id
		Dec.clase = DecVar.clase
		Dec.props = addPropiedad(DecVar.props, "nivel", Dec.nh)
		Dec.dir = Dec.dirh + DecVar.props.tam
		Dec.n = Dec.nh
		
		Dec.err = DecVar.err
	
		Dec.cod = DecVar.cod
		Dec.etq = DecVar.etq
*/		
	}.
%Dec(+Tsh,+Dirh,+Nh,-N,-Pends,-ID,-Clase,-Dir,-Props,-Error,+Etqh,-Etq,-Cod)
dec(TshDec,DirhDec,NhDec,NhDec,PendsDec,IDDec,ClaseDec,DirhDec,PropsDec,ErrDec,EtqhDec,EtqDec,CodDec) --> 
/*
	DecTipo.tsh = Dec.tsh
	
	DecTipo.etqh = Dec.etqh
*/

	decTipo(TshDec,_,PendsDec,IDDec,ClaseDec,PropsDecTipo,ErrDec,EtqhDec,EtqDec,CodDec),
	{		
	/*
		Dec.pends = DecTipo.pends
		Dec.id = DecTipo.id
		Dec.clase = DecTipo.clase
		Dec.props = addPropiedad(DecTipo.props, "nivel", Dec.nh)
		Dec.dir = Dec.dirh
		Dec.n = Dec.nh
		
		Dec.err = DecTipo.err
		
		Dec.cod = DecTipo.cod
		Dec.etq = DecTipo.etq
	*/
		agregaPropiedad(PropsDecTipo,nivel,NhDec,PropsDec)
	}.
%Dec(+Tsh,+Dirh,+Nh,-N,-Pends,-ID,-Clase,-Dir,-Props,-Error,+Etqh,-Etq,-Cod)
dec(TshDec,DirhDec,NhDec,NDec,PendsDec,IDDec,ClaseDec,DirhDec,PropsDec,ErrDec,EtqhDec,EtqDec,CodDec) --> 
/*
		DecFun.tsh = Dec.tsh
		DecFun.nh = Dec.nh
		
		DecFun.etqh = Dec.etqh

*/
	decFun(TshDec,NhDec,NDec,PendsDec,IDDec,ClaseDec,PropsDecFun,ErrDec,EtqhDec,EtqDec,CodDec),
	{
	/*
		Dec.pends = DecFun.pends
		Dec.id = DecFun.id
		Dec.clase = DecFun.clase
		Dec.dir = Dec.dirh
		Dec.props = addPropiedad(DecFun.props, "nivel", Dec.nh)
		Dec.n = DecFun.n
		
		Dec.err = DecFun.err
		
		Dec.cod = DecFun.cod
		Dec.etq = DecFun.etq
	*/
		agregaPropiedad(PropsDecFun,nivel,NhDec,PropsDec)
	}.

%DecTipo(+Tsh,-N,-Pends,-ID,-Clase,-Props,-Error,+Etqh,-Etq,-Cod)
decTipo(TshDecTipo,_,PendsDecTipo,IDDecTipo,ClaseDecTipo,PropsDTipo,ErrDecTipo,EtqhDecTipo,EtqhDecTipo,CodDecTipo) --> 
	%tipo 
	[(tipo,_,_)],
/*
		DTipo.tsh = DecTipo.tsh
*/
	dTipo(TshDecTipo, PropsDTipo,_,ErrDTipo),	
	id(IDDecTipo,_,_),
	% ;
	[(pyc,_,_)],
	{
	/*
		DecTipo.pends = if (DTipo.t==puntero,
								if(existeID(DTipo(0).tsh, DTipo(1).id), {}, {DTipo(1).id})
								{})
		DecTipo.id = ID.lex
		DecTipo.props = DTipo.props.t
		DecTipo.clase = "tipo"
		
		DecTipo.err = DTipo.err v existeID(DTipo.tsh, ID.lex)
		
		DecTipo.cod = ""
		DecTipo.etq = DecTipo.etqh
	*/
		dameAtrib(PropsDTipo,t,T),		
		/*
		dameAtrib(PropsDTipo,t,P1),
		PropsecTipo=[(t,P1)],
		ClaseDecTipo=tipo,
		*/
		existeID(TshDecTipo,IDDecTipo,ExisteID),		
		or([ErrDTipo,ExisteID],ErrDecTipo),		
		CodDecTipo=[],
		ClaseDecTipo=tipo,
		(igual(T,puntero,true) ->
			(existeID(TshDecTipo,IDDecTipo,true) ->	
				PendsDecTipo=[]
				; 
				PendsDecTipo=[IDDecTipo]
			)
			; 
			(PendsDecTipo=[])
		),
		ClaseDecTipo=tipo
	}.
	
%DecVar(+Tsh,-N,-Pends,-ID,-Clase,-Props,-Error,+Etqh,-Etq,-Cod)
decVar(TshDecVar,NhDecVar,PendsDecVar,IDDecVar,ClaseDecVar,PropsDecVar,ErrDecVar,EtqhDecVar,EtqhDecVar,CodDecVar) --> 
/*
		DTipo.tsh = DecVar.tsh
*/
	dTipo(TshDecVar,PropsDecVar,_,ErrDTipo),
	id(IDDecVar,_,_),
	% ;
	[(pyc,_,_)],		
	{
	/*
		DecVar.pends = {}
		DecVar.id = ID.lex
		DecVar.props = <t:DTipo.props.t, tam:DTipo.props.tam>
		DecVar.clase = var
		
		DecVar.err = DTipo.err v (existeID(DTipo.tsh,ID.lex) && DTipo.tsh[ID.lex].props.nivel == DecVar.nh)
		
		DecVar.cod = ""
		DecVar.etq = DecVar.etqh
	*/
		PendsDecVar = [],
		%dameAtrib(PropsDTipo,t,PropsTDTipo),
		%dameAtrib(PropsDTipo,tam,PropsTamDTipo),
		%PropsDecVar = [(t,PropsTDTipo),(tam,PropsTamDTipo)],
		ClaseDecVar = var,
		

		(existeID(TshDecVar,IDDecVar,true) -> 	(buscaEnTabla(TshDecVar,IDDecVar,E),
												 dameAtrib(E,props,Props),
												 dameAtrib(Props,nivel,NivelDecID),
												 igual(NivelDecID,NhDecVar,Sol1)
												)
												;
												Sol1=false),		
		or([ErrDTipo,Sol1],ErrDecVar),
		
		CodDecVar = []
	}.
	
%DecFun(-Tsh,-Nh,+N,+Pends,+ID,+Clase,+Props,-Error,+Etqh,-Etq,-Cod)
decFun(TshDecFun,NhDecFun,NDecFun,PendsDecFun,IDDecFun,ClaseDecFun,PropsDecFun,ErrDecFun,EtqhDecFun,EtqDecFun,CodDecFun) --> 
	% fun 
	[(inifun,_,_)],
	id(IDDecFun,_,_), 
	{
	/*
		FParams.tsh = CreaTS(DecFun.tsh)
		%Dirh = 2 porque CP apunta al comienzo del RA y primero se apila: DirRet y AntDisplay (Asi que, no es 0, no es 1, es 2)
		FParams.dirh = 2 
		FParams.nh = DecFun.nh + 1
	*/	
		creaTS(TshFParams,TshDecFun),
		DirhFParams is 2,
		NhFParams is NhDecFun + 1
	},
	%FParams(+Tsh,+Dirh,+Nh,-TS,-Dir,-Params)
	fParams(TshFParams,DirhFParams,NhFParams,TSFParams,DirFParams,ParamsFParams),
/*
		RDecFun.tsh = DecFun.tsh
		
		RDecFun.etqh = DecFun.etqh
*/
	rDecFun(TshDecFun,PropsRDecFun,RetRDecFun,ErrRDecFun,EtqhDecFun,EtqRDecFun,CodRDecFun),
	{
	/*
		Bloque.tsh = anhadeID(FParams.ts, ID.lex,addPropiedad(DecFun.props, "nivel", DecFun.nh + 1))
		Bloque.dirh = FParams.dir
		Bloque.nh = DecFun.nh + 1
				
		Bloque.etqh = RDecFun.etq		
	*/
		NhDecFun1 is NhDecFun + 1,
		agregaPropiedad(PropsRDecFun,nivel,NhDecFun1,PropsDec),
		%TODO: OJO, esta funcion es rara. No sigue la norma de anhadeID. Ver como devolvemos las propiedades
		anhadeID(TSFParams,IDDecFun,PropsDec,TshBloque)
	},
	bloque(TshBloque,DirFParams,NhDecFun1,NDecFun,PendsDecFun,RetRDecFun,ErrBloque,EtqRDecFun,EtqDecFun,CodBloque,InicioBloque),
	% end 
	[(fin,_,_)],
	id(IDDecFun1,_,_),
	% ;
	[(pyc,_,_)],
	{	
	/*
		DecFun.pends = Bloque.pends
		DecFun.id = ID(0).lex
		DecFun.clase = fun
		DecFun.props = <t:fun, params: FParams.params>, ret: RDecFun.props.t, inicio: Bloque.inicio >
		DecFun.n = Bloque.n
				
		DecFun.err = FParams.err v Bloque.err v (existeID(FParams.ts,ID(0).lex) &&  FParams.ts[ID(0).lex].props.nivel == DecFun.nh) 
			v RDecFun.err v (ID(0).lex != ID(1).lex)
			TODO: Donde esta el FParams.err¿?¿?¿?
		DecFun.etq = Bloque.etq				
		DecFun.cod = Bloque.cod || RDecFun.cod	
	*/
		ClaseDecFun = fun,
		dameAtrib(PropsRDecFun,t,PropsTRDecFun),
		PropsDecFun = [(t,fun),(params,ParamsFParams),(ret,PropsTRDecFun),(inicio,InicioBloque)],
		existeID(TSFParams,IDDecFun,ExisteID),		
		buscaEnTabla(TSFParams,IDDecFun,E),
		dameAtrib(E,props,Props),
		dameAtrib(Props,nivel,NivelDecID),		
		igual(NivelDecID,NhDecFun,IgualNivel),		
		and([ExisteID,IgualNivel],Sol1),		
		distinto(IDDecFun,IDDecFun1,IdentIguales),
		or([ErrBloque,Sol1,ErrRDecFun,IdentIguales],ErrDecFun),
		
		agrega([CodBloque,CodRDecFun],CodDecFun)
	}.
	
%DTipo(+Tsh,-Props,-Pends,-Error)
dTipo(_,PropsDTipo,PendsDTipo,ErrDTipo) --> 
	[(tInt,_,_)],
	{
	/*
		DTipo.props = <t:int, tam:1>
		DTipo.pends = {}
		
		DTipo.err = False
	*/
		PropsDTipo = [(t,int),(tam,1)],
		PendsDTipo = [],
		
		ErrDTipo = false
	}.
%DTipo(+Tsh,-Props,-Pends,-Error)	
dTipo(_,PropsDTipo,PendsDTipo,ErrDTipo) --> 
	[(tReal,_,_)],
	{
	/*
		DTipo.props = <t:real, tam:1>
		DTipo.pends = {}
		
		DTipo.err = False
	*/
		PropsDTipo = [(t,real),(tam,1)],
		PendsDTipo = [],
		
		ErrDTipo = false
	}.
%DTipo(+Tsh,-Props,-Pends,-Error)
dTipo(TshDTipo,PropsDTipo,PendsDTipo,ErrDTipo) --> 
	id(LexID,_,_),
	{
	/*
		DTipo.props = <t:ref, id:ID.lex, tam:DTipo.tsh[ref!(DTipo.tsh, ID.lex)].props.tam> 
		DTipo.pends = {}
		
		DTipo.err = if(existeID(DTipo.tsh,ID.lex),DTipo.tsh[ID.lex].clase != "tipo",False)
	*/
		PendsDTipo=[],
		buscaEnTabla(TshDTipo,LexID,E),
		dameAtrib(E,props,Props),
		dameAtrib(Props,tam,Tam),		
		PropsDTipo = [(t,ref),(id,LexID),(tam,Tam)],		
		dameAtrib(E,clase,Clase),
		(existeID(TshDTipo,LexID,true) -> 	(dameAtrib(E,clase,Clase),distinto(Clase,tipo,true) ->
												ErrDTipo=true
											 ;	ErrDTipo=false
											) 
											; ErrDTipo=false)
	}.
%DTipo(+Tsh,-Props,-Pends,-Error)	
dTipo(TshDTipo0,PropsDTipo0,PendsDTipo0,ErrDTipo0) --> 
/*
	DTipo(1).tsh = DTipo(0).tsh
*/
	tipoRet(TshDTipo0,PropsDTipo1,_),
/*	
	[ EntPos ]
*/
	[(cap,_,_)], entpos(LexEntPos,_,_), [(ccierre,_,_)],
	{
	/*
		DTipo(0).props = <t:array, nelems:getValor(EntPos.lex), tbase:DTipo(1).props.t,tam: getValor(EntPos.lex)*DTipo(1).props.tam>
		DTipo.pends = {}
		
		DTipo(0).err = DTipo(1).err TODO
	*/
		dameAtrib(PropsDTipo1,t,PropsTDTipo1),
		dameAtrib(PropsDTipo1,tam,PropsTamDTipo1),
		TamDTipo0 is LexEntPos*PropsTamDTipo1,
		PropsDTipo0 = [(t,array),(nelems,LexEntPos),(tbase,PropsTDTipo1),(tam,TamDTipo0)],
		PendsDTipo0 = [],
		ErrDTipo0 = false
	}.
%DTipo(+Tsh,-Props,-Pends,-Error)	
dTipo(TshDTipo0,PropsDTipo0,_,ErrDTipo0) --> 
/*
	DTipo(1).tsh = DTipo(0).tsh
*/
	%pointer 
	[(puntero,_,_)],
	dTipo(TshDTipo0,PropsDTipo1,_,ErrDTipo0),
	{
	/*
		DTipo(0).props = <t:puntero, tbase:DTipo(1).props.t, tam:1>
		DTipo(0).pends = if(existeID(DTipo(0).tsh, DTipo(1).id), {}, {DTipo(1).id}) TODO <-- Hecho arriba en produccion decTipo
		
		DTipo(0).err = DTipo(1).err
	*/
		dameAtrib(PropsDTipo1,t,PropsTDTipo1),
		PropsDTipo0 = [(t,puntero),(tbase,PropsTDTipo1),(tam,1)]
	}.
%DTipo(+Tsh,-Props,-Pends,-Error)	
dTipo(TshDTipo,PropsDTipo,PendsDTipo,ErrDTipo) -->
	%rec 
	[(iniRec,_,_)],
	{
	/*
		Campos.tsh = DTipo.tsh
		Campos.desh = 0
	*/
		DeshCampos is 0
	},
	campos(TshDTipo,DeshCampos,_,CamposCampos,TamCampos,ErrDTipo),
	%endrec
	[(finRec,_,_)],
	{
	/*
		DTipo.props = <t:rec, campos:Campos.campos, tam:Campos.tam>
		DTipo.pends = {}
		
		DTipo.err = Campos.err
	*/
		PropsDTipo = [(t,rec),(campos,CamposCampos),(tam,TamCampos)],
		PendsDTipo = []
	}.

%Campos(+Tsh,+Desh,-Des,-Campos,-Tam,-Error)
campos(TshCampos,DeshCampos,DesCampos,CamposCampos,TamCampos,ErrCampos) --> 
/*
		Campo.tsh = Campos.tsh
*/
	campo(TshCampos,CampoCampo,TamCampo,DeshCampos,ErrCampo),
	% ; 
	[(pyc,_,_)],
	{
	/*
		RCampos.tsh = Campos.tsh
		RCampos.desh = Campos.desh + Campo.tam		
	*/
		DeshRCampos is DeshCampos + TamCampo
	},
	rCampos(TshCampos,DeshRCampos,DesCampos,CamposRCampos,TamRCampos,ErrRCampos),
	{
	/*
		Campos.campos = [Campo.campo] ++ RCampos.campos 
		Campos.des = RCampos.des 
		Campos.tam = RCampos.tam + Campo.tam
		
		Campos.err = Campo.err v RCampos.err v existeCampo(RCampos.campos,Campo.id)
	*/
		agrega([[CampoCampo],CamposRCampos],CamposCampos),
		TamCampos is TamRCampos + TamCampo,

		atribCampo(CampoCampo,id,IDCampo),
		existeCampo(CamposRCampos,IDCampo,ExisteCampo),
		or([ErrCampo,ErrRCampos,ExisteCampo],ErrCampos)
	}.

%RCampos(+Tsh,+Desh,-Des,-Campos,-Tam,-Error)	
rCampos(TshRCampos0,DeshRCampos0,DesRCampos0,CamposRCampos0,TamRCampos0,ErrRCampos0) --> 
/*
		Campo.tsh = RCampos(0).tsh
*/
	campo(TshRCampos0,CampoCampo,TamCampo,DeshRCampos0,ErrCampo),
	% ; 
	[(pyc,_,_)],
	{
	/*
		RCampos(1).tsh = RCampos(0).tsh
		RCampos(1).desh = RCampos(0).desh + Campo.tam
	*/
		DeshRCampos1 is DeshRCampos0 + TamCampo
	},
	rCampos(TshRCampos0,DeshRCampos1,DesRCampos0,CamposRCampos1,TamRCampos1,ErrRCampos1),
	{	
	/*
		RCampos(0).campos = [Campo.campo] ++ RCampos(1).campos 
		RCampos(0).des = RCampos(1).des 
		RCampos(0).tam = RCampos(1).tam + Campo.tam
		
		RCampos(0).err = Campo.err v RCampos(1).err v existeCampo(RCampos(1).campos,Campo.id)
	*/
		agrega([[CampoCampo],CamposRCampos1],CamposRCampos0),
		TamRCampos0 is TamRCampos1 + TamCampo,
		
		atrCampo(CampoCampo,id,IDCampo),
		existeCampo(CamposRCampos1,IDCampo,ExisteCampo),
		or([ErrCampo,ErrRCampos1,ExisteCampo],ErrRCampos0)
	}.

%RCampos(+Tsh,+Desh,-Des,-Campos,-Tam,-Error)
rCampos(_,DeshRCampos,DeshRCampos,CamposRCampos,TamRCampos,ErrRCampos) --> 
	%lambda
	[],
	{
	/*
		RCampos.campos = []
		RCampos.des = RCampos.desh 
		RCampos.tam = 0
		
		RCampos.err = False
	*/
		CamposRCampos = [],
		TamRCampos is 0,
		
		ErrRCampos = false
	}.

%Campo(+Tsh,-Campo,-Tam,-Error)
campo(TshCampo,CampoCampo,TamCampo,DeshCampo,ErrCampo) --> 
/*
		DTipo.tsh = Campo.tsh
*/
	dTipo(TshCampo,PropsDTipo,_,ErrCampo),
	id(LexID,_,_),
	{
	/*
		Campo.campo = <id:ID.lex, tipo:DTipo.props.t, desp=Campo.desh>
		Campo.tam = DTipo.props.tam
		
		Campo.err = DTipo.err
	*/
		dameAtrib(PropsDTipo,t,PropsTDTipo),
		dameAtrib(PropsDTipo,tam,TamCampo),
		CampoCampo = [(id,LexID),(tipo,PropsTDTipo),(desp,DeshCampo)]
	}.

%FParams(+Tsh,+Dirh,+Nh,-TS,-Dir,-Params,-Error)
fParams(TshFParams,DirhFParams,NhFParams,TSFParams,DirFParams,ParamsFParams,ErrFParams) --> 
/*
		LFParams.tsh = FParams.tsh
		LFParams.dirh = FParams.dirh
		LFParams.nh = FParams.nh
*/
	%( LFParams )
	[(pap,_,_)],
	lFParams(TshFParams,DirhFParams,NhFParams,TSFParams,DirFParams,ParamsFParams,ErrFParams),
	[(pcierre,_,_)].
/*
		FParams.ts = LFParams.ts
		FParams.dir = LFParams.dir
		FParams.params = LFParams.params
		
		Fparams.err = LFParams.err
*/

%LFParams(+Tsh,+Dirh,+Nh,-TS,-Dir,-Params,-Error)
lFParams(TshLFParams,DirhLFParams,NhLFParams,TSLFParams,DirLFParams,ParamsLFParams,ErrLFParams) --> 
/*
		FParam.tsh = LFParams.tsh	
		FParam.nh = LFParams.nh
		FParam.dirh = LFParams.dirh
*/
	fParam(TshLFParams,DirhLFParams,NhLFParams,ClaseFParam,IDFParam,PropsFParam,ParamFParam,ErrFParam),
	{
	/*
		RLFParams.tsh = anhadeID(LFParams.tsh, FParam.id, FParam.clase, LFParams.dirh, FParam.props)
		RLFParams.dirh = LFParams.dirh + FParam.props.tam
		RLFParams.nh = LFParams.nh
	*/
		anhadeID(TshLFParams,IDFParam,ClaseFParam,DirhLFParams,PropsFParam,TshRLFParams),
		dameAtrib(PropsFParam,tam,PropsTamFParam),
		DirhRLFParams = DirhLFParams + PropsTamFParam
	},
	rLFParams(TshRLFParams,DirhRLFParams,NhLFParams,TSLFParams,DirLFParams,ParamsRLFParams,ErrRLFParams),
	{	
	/*
		LFParams.ts = RLFParams.ts
		LFParams.dir = RLFParams.dir
		LFParams.params  = [FParam.param] ++ RLFParams.params
		
		LFParams.err = RLFParams.err v FParam.err v (existeID(RLFParams.ts,FParam.id) && 
						RLFParams.ts[FParam.id].props.nivel == LFParams.nh)
	*/
		agrega([ParamFParam],ParamsRLFParams, ParamsLFParams),

		existeID(TSLFParams,IDFParam,ExisteID),		
		%TODO:RLFParams.ts[FParam.id].props.nivel
		buscaenTabla(TshRLFParams,IDFParam,E),
		dameAtrib(E,props,Props),
		dameAtrib(Props,nivel,NivelRLFParams),
		igual(NivelRLFParams,NhLFParams,IgualNivel),		
		and([ExisteID,IgualNivel],Sol1),
		or([ErrRLFParams,ErrFParam,Sol1],ErrLFParams)
	}.

%LFParams(+Tsh,+Dirh,+Nh,-TS,-Dir,-Params,-Error)
lFParams(TshLFParams,DirhLFParams,_,TshLFParams,DirhLFParams,ParamsLFParams,ErrLFParams) --> 
	%lambda	
	[],
	{
	/*
		LFParams.ts = LFParams.tsh
		LFParams.dir = LFParams.dirh
		LFParams.params = []
		
		LFParams.err = False	
	*/
		ParamsLFParams = [],
		
		ErrLFParams = false
	}.

%RLFParams(+Tsh,+Dirh,+Nh,-TS,-Dir,-Params,-Error)
rLFParams(TshRLFParams0,DirhRLFParams0,NhRLFParams0,TSRLFParams0,DirRLFParams0,ParamsRLFParams0,ErrRLFParams0) --> 
	% , 
	[(coma,_,_)],
/*
		FParam.tsh = RLFParams(0).tsh	
		FParam.nh = RLFParams(0).nh
		FParam.dirh =RLFParams(0).dirh
*/
	fParam(TshRLFParams,DirhRLFParams0,NhRLFParams0,ClaseFParam,IDFParam,PropsFParam,ParamFParam),
	{
	/*
		RLFParams(1).tsh = anhadeID(RLFParams(0).tsh, FParam.id, FParam.clase, RLFParams(0).dirh, FParam.props)
		RLFParams(1).dirh = RLFParams(0).dirh + FParam.props.tam
		RLFParams(1).nh = RLFParams(0).nh
	*/
		DirhRLFParams1 is  DirhRLFParams0 + ParamFParam
	},
	rLFParams(TshRLFParams1,DirhRLFParams1,NhRLFParams0,TSRLFParams0,DirRLFParams0,ParamsRLFParams1),
	{
	/*	
		RLFParams(0).ts = RLFParams(1).ts
		RLFParams(0).dir = RLFParams(1).dir
		RLFParams(0).params  = [FParam.param] ++ RLFParams(1).params
		
		RLFParams(0).err = RLFParams(1).err v FParam.err v (existeID(RLFParams(1).ts,FParam.id) && 
					RLFParams(1).ts[FParam.id].props.nivel == RLFParams(0).nh)
	*/
		existeID(TshRLFParams1,IDFParam,Existe),
		buscaEnTabla(TSRLFParams1,IDFParam,E),
		dameAtrib(E,props,Props),
		dameAtrib(Props,nivel,Nivel),
		igual(Nivel,NhRLFParams0,Eq),
		and([Existe,Eq],Ex),
		or([ErrRLFParams1,ErrFParam,Ex],ErrRLFParams0),
		agrega([ParamFParam],ParamsRLFParams1,ParamsRLFParams0)
		
		
	}.
%RLFParams(+Tsh,+Dirh,+Nh,-TS,-Dir,-Params,-Error)
rLFParams(TshRLFParams,DirhRLFParams,TshRLFParams,DirhRLFParams,ParamsRLFParams,ErrRLFParams) --> 
	%lambda
	[],
	{
	/*
		RLFParams.ts = RLFParams.tsh
		RLFParams.dir = RLFParams.dirh
		RLFParams.params  = []
		
		RLFParams.err = False
	*/
		ParamsRLFParams = [],
		
		ErrRLFParams = false
	}.

%FParam(+Tsh,+Dirh,+Nh,-Clase,-ID,-Props,-Param,-Error)
fParam(TShFParam,DirhFParam,NhFParam,ClaseFParam,IDFParam,PropsFParam,ParamFParam,ErrFParam) --> 
/*
		TipoFun.tsh = FParam.tsh
*/
	tipoFun(TShFParam,PropsTipoFun,ErrFParam),
	rFParam(IDFParam,ClaseFParam),
	{
	/*
		FParam.id = RFParam.id
		FParam.clase = RFParam.clase
		FParam.props = <t: TipoFun.props.t, tam: TipoFun.props.tam, 
						nivel: FParam.nh> 
		FParam.param = if (RFParam.clase == "PVar", <modo: var, tipo: TipoFun.props.t, dir: FParam.dirh>,
										       <modo: val, tipo: TipoFun.props.t, dir: FParam.dirh>)
										       
		FParam.err = TipoFun.err
	*/
		dameAtrib(PropsTipoFun,t,PropsTTipoFun),
		dameAtrib(PropsTipoFun,tam,PropsTamTipoFun),
		PropsFParam = [(t,PropsTTipoFun),(tam,PropsTamTipoFun),(nivel,NhFParam)],
		dameAtrib(PropsTipoFun,t,T),
		(igual(ClaseFParam,pvar,true) -> ParamFParam=[(modo,var),(tipo,T),(dir,DirhFParam)]
										; ParamFParam=[(modo,val),(tipo,T),(dir,DirhFParam)])
		
	}.



%RFParam(-ID,-Clase)	
rFParam(IDRFParam,ClaseRFParam) --> 
	% & 
	[(amp,_,_)], 
	id(IDRFParam,_,_),
	{
	/*
		RFParam.id = ID.lex
		RFParam.clase = "PVar"
	*/
		ClaseRFParam = pvar
	}.
%RFParam(-ID,-Clase)		
rFParam(IDRFParam,ClaseRFParam) -->	
	id(IDRFParam,_,_),
	{
	/*
		RFParam.id = ID.lex
		RFParam.clase = "Var"
	*/
		ClaseRFParam = var
	}.

%TipoFun(+TS,-Props,-Error)	
tipoFun(_,PropsTipoFun,ErrTipoFun) --> 
	[(tInt,_,_)],
	{
	/*
		TipoFun.props = <t:int, tam:1>
		
		TipoFun.err = False	
	*/
		PropsTipoFun = [(t,int),(tam,1)],
		
		ErrTipoFun = false
		
	}.
%TipoFun(+TS,-Props,-Error)	
tipoFun(_,PropsTipoFun,ErrTipoFun) --> 
	[(tReal,_,_)],
	{
	/*
		TipoFun.props = <t:real, tam:1>

		TipoFun.err = False			
	*/
		PropsTipoFun = [(t,real),(tam,1)],
		
		ErrTipoFun = false
	}.
%TipoFun(-Props,-Error)		%TipoFun(+TS,-Props,-Error)	
tipoFun(TSTipoFun,PropsTipoFun,ErrTipoFun) --> 
	id(LexID,_,_),
	{
	/*
		TipoFun.props = <t:ref, id:ID.lex, tam:TipoFun.tsh[ref!(TipoFun.tsh, ID.lex)].props.tam>
		
		TipoFun.err = TipoFun.tsh[ID.lex].clase != "tipo" TODO: Seguro que tiene que ser != tipo ???
	*/
		ref(TSTipoFun,LexID,ID1),
		buscaEnTabla(TSTipoFun,ID1,E),
		dameAtrib(E,props,Props),
		dameAtrib(Props,tam,Tam),
		PropsTipoFun = [(t,ref),(id,LexID),(tam,Tam)],
		
		buscaEnTabla(TSTipoFun,LexID,E1),
		dameAtrib(E1,clase,Clase),
		distinto(Clase,tipo,ErrTipoFun)
	}.

%Bloque(+Tsh,+Dirh,+Nh,-N,-Pends,+Reth,-Error,+Etqh,-Etq,-Cod,-Inicio)
bloque(TshBloque,DirhBloque,NhBloque,NBloque,PendsBloque,RethBloque,ErrBloque,EtqhBloque,EtqBloque,CodBloque,EtqDecs) --> 
	{
	/*
		Decs.tsh = Bloque.tsh
		Decs.dirh = Bloque.dirh
		Decs.nh = Bloque.nh
		Decs.pendh = {}
		
		Decs.etqh = Bloque.etqh
	*/
		PendshDecs = []
	},
	decs(TshBloque,DirhBloque,NhBloque,NBloque,PendshDecs,PendsBloque,TSDecs,DirDecs,ErrDecs,EtqhBloque,EtqDecs,CodDecs),
	{
	/*
		ActsFun.nh = Bloque.nh
		ActsFun.ts = comprobarAlias(Decs.ts)
		TODO: comprobarAlias(Decs.ts)
		
		ActsFun.reth = Bloque.reth
		
		ActsFun.etqh = Decs.etq + LongPrologo()
	*/
		comprobarAlias(TSDecs,TSActs),
		
		longPrologo(LongPrologo),
		EtqhActsFun is EtqDecs + LongPrologo
	},
	actsFun(TSActs,NhBloque,RethBloque,ErrActsFun,EtqhActsFun,EtqActsFun,CodActsFun),
	{
	/*
		Bloque.pends = Decs.pends
		Bloque.n = Decs.n
		
		Bloque.err = Decs.err v ActsFun.err
	
		Bloque.cod = Decs.cod || Prologo(Bloque.nh, Decs.dir) || ActsFun.cod || Epilogo(Bloque.nh) || Ir_ind
		Bloque.etq = ActsFun.etq + LongEpilogo() + 1
		Bloque.inicio = Decs.etq
	*/
		or([ErrDecs,ErrActsFun],ErrBloque),
		

		prologo(NhBloque,DirDecs,Prologo),
		epilogo(NhBloque,Epilogo),
		agrega([CodDecs,Prologo,CodActsFun,Epilogo,[ir_ind]],CodBloque),
		
		longEpilogo(LongEpilogo),
		EtqBloque is EtqActsFun + LongEpilogo + 1
	}.
		
	
%ActsFun(-Ts,-Nh,+Reth,-Error,+Etqh,-Etq,-Cod)
actsFun(TSActsFun,NhActsFun,RethActsFun,ErrActsFun,EtqhActsFun,EtqActsFun,CodActsFun) --> 
/*
		Acts.nh = ActsFun.nh
		Acts.ts = ActsFun.ts
		
		Acts.reth = ActsFun.reth
		
		Acts.etqh = ActsFun.etqh
		
*/
	acts(TSActsFun,NhActsFun,RethActsFun,ErrActsFun,EtqhActsFun,EtqActs,CodActs),
	{
	/*
			ActsFun.err = Acts.err
		
			ActsFun.cod = if(ActsFun.reth = puntero,
								Acts.cod || "Apila_dir (-1)",
								if(ActsFun.reth = int,
									Acts.cod || "ApilaI 0",
									Acts.cod || "ApilaR 0"))
			ActsFun.etq = Acts.etq + 1		
	*/
		EtqActsFun is EtqActs + 1,
		
		(igual(RethActsFun,puntero,true) ->	agrega([CodActs,[apila_i(-1)]],CodActsFun)
											; (igual(RethActsFun,int,true) ->
												agrega([CodActs,[apila_i(0)]],CodActsFun)
												; agrega([CodActs,[apila_r(0)]],CodActsFun)
												))
	}.										  
%ActsFun(-Ts,-Nh,+Reth,-Error,+Etqh,-Etq,-Cod)
actsFun(_,_,RethActsFun,ErrActsFun,EtqhActsFun,EtqActsFun,CodActsFun) --> 
	%lambda	
	[],
	{
	/*
		ActsFun.err = False

		ActsFun.cod = if(ActsFun.reth = puntero,
				"Apila_dir (-1)",
				if(ActsFun.reth = int,
					"ApilaI 0",
					"ApilaR 0"))
		ActsFun.etq = ActsFun.etqh + 1
	*/
		(igual(RethActsFun,puntero,true) ->	agrega([[apila_dir(-1)]],CodActsFun)
											; (igual(RethActsFun,int,true) ->	agrega([[apila_i(0)]],CodActsFun)
																				; agrega([[apila_dir(-1)]],CodActsFun))),
		ErrActsFun = false,
		
		EtqActsFun is EtqhActsFun + 1
	}.
	
funActsFun1(RethActsFun, Output) :-
    (igual(RethActsFun,puntero) ->
        Output = apila_dir(-1)
    ;   (igual(RethActsFun,int) ->
            Output = apilaI(0)
        ;   Output = apilaR(0)
        )
    ).

	
%RDecFun(+Ts,-Props,-Retorno,-Error,+Etqh,-Etq,-Cod)
rDecFun(TSRDecFun,PropsRDecFun,RetRDecFun,ErrRDecFun,EtqhRDecFun,EtqhRDecFun,CodRDecFun) --> 
/*
		TipoRet.tsh = RDecFun.tsh
*/
	% returns 
	[(retornoFun,_,_)],
	tipoRet(TSRDecFun,PropsRDecFun,ErrRDecFun),
	{
	/*
		RDecFun.props = TipoRet.props

		RDecFun.ret = TipoRet.props.t
		RDecFun.err = TipoRet.err
		
		RDecFun.cod  = ""
		RDecFun.etq = RDecFun.etqh 		
	*/
		dameAtrib(PropsRDecFun,t,RetRDecFun),
		
		CodRDecFun = []
	}.

%RDecFun(+Ts,-Props,-Retorno,-Error,+Etqh,-Etq,-Cod)
rDecFun(_,PropsRDecFun,RetRDecFun,ErrRDecFun,EtqhRDecFun,EtqRDecFun,CodRDecFun) --> 
	%lambda
	[],
	{
	/*
		RDecFun.props = <t:int, tam:1>
		
		RDecFun.ret = int
		RDecFun.err = False
		
		RDecFun.cod  = "ApilaI 0"
		RDecFun.etq = RDecFun.etqh + 1		
	*/
		PropsRDecFun = [(t,int),(tam,1)],

		RetRDecFun = int,
		ErrRDecFun = false,
		
		CodRDecFun = [apilaI(0)],
		EtqRDecFun is EtqhRDecFun + 1
	}.
	
%TipoRet(+TS,-Props,-Error)
tipoRet(_,PropsTipoRet,ErrTipoRet) --> 
	[(tInt,_,_)],
	{
	/*
		TipoRet.props = <t:int, tam:1>
		
		TipoRet.err = False
	*/
		PropsTipoRet = [(t,int),(tam,1)],
		
		ErrTipoRet = false
	}.
%TipoRet(+TS,-Props,-Error)
tipoRet(_,PropsTipoRet,ErrTipoRet) --> 
	[(tReal,_,_)],
	{
	/*
		TipoRet.props = <t:real, tam:1>
		
		TipoRet.err = False
	*/
		PropsTipoRet = [(t,real),(tam,1)],
		
		ErrTipoRet = false
	}.
%TipoRet(+TS,-Props,-Error)
tipoRet(TSTipoRet,PropsTipoRet,ErrTipoRet) --> 
	id(LexID,_,_),
	{
	/*
		TipoRet.props = <t:ref, id:ID.lex, tam: TipoRet.tsh[ref!(TipoRet.tsh,ID.lex)].props.tam>
		TipoRet.tsh[ref!(TipoRet.tsh,ID.lex)].props.tam
		
		TipoRet.err = TipoRet.tsh[ID.lex].props.t != puntero
	*/
		%TODO ref
		ref(TSTipoRet,LexID,ID1),
		buscaEnTabla(TSTipoRet,ID1,E),
		dameAtrib(E,props,Props),
		dameAtrib(Props,tam,Tam),
		dameAtrib(Props,t,TPropsTipoRet),
		PropsTipoRet = [(t,ref),(id,LexID),(tam,Tam)],
		
		distinto(TPropsTipoRet,puntero,ErrTipoRet)
	}.

%id(-Lexema,-Linea token,-Posicion token)                            
id(Lex,L,P) -->     [(id(Lex),L,P)].
%entpos(-Valor,-Linea token,-Posicion token)                            
entpos(Valor,L,P) -->       [(int(Valor),L,P)].
%real(-Valor,-Linea token,-Posicion token)                            
real(Valor,L,P) -->[(real(Valor),L,P)].	

%Mem(+TS,-Props,+Etqh,-Etq,-Cod)
mem(TSMem,PropsMem,EtqhMem,EtqMem,CodMem) --> 
	id(LexID,_,_),
	{
	/*
		RMem.tsh = Mem.tsh
		RMem.propsh = if (existeID(Mem.tsh,ID.lex),
					if (Mem.tsh[ID.lex].clase == var,
						Mem.tsh[ref!(Mem.tsh, ID.lex)].props,
						<t: error>),
					<t: error>)

		RMem.etqh = Mem.etqh
	*/
		(existeID(TSMem,LexID,true) ->	(buscaEnTabla(TSMem,LexID,E),dameAtrib(E,clase,Clase), igual(Clase,var,true) ->
											(ref(TSMem,LexID,ID1),buscaEnTabla(TSMem,ID1,E1),dameAtrib(E1,props,PropshRMem))
											;
											(PropshRMem=[(t,error)],ID1=LexID)
										))
	},
	rMem(TSMem,PropshRMem,PropsMem,EtqhMem,EtqRMem,CodRMem),
	{
	/*
		Mem.props = RMem.props

		Mem.cod = "AccesoVar(ID.lex)" || RMem.cod
		Mem.etq = RMem.etq + LongAccesoVar() <------------- longAccesoVares para FUNCIONES!!!
	*/
		accesoVar(TSMem,LexID,AccesoVar),
		agrega([AccesoVar,CodRMem],CodMem),
		EtqMem is EtqRMem + 1
	}.

%RMem(+TS,+Propsh,-Props,+Etqh,-Etq,-Cod)
rMem(TSRMem,PropshRMem0,PropsRMem0,EtqhRMem0,EtqRMem0,CodRMem0) --> 
	% ^ 
	[(sombrero,_,_)],
	{
	/*
		RMEm(1).tsh = RMem(0).tsh
		RMem(1).propsh = if (RMem(0).propsh.t == puntero,
					RMem(0).propsh.tbase,
					<t: error>

		RMem(1).etqh = RMem(0).etqh	
	*/
		dameAtrib(PropshRMem0,t,Props),
		(igual(Props,puntero,true) -> 	dameAtrib(PropshRMem0,tbase,PropshRMem1)
										; PropshRMem1=[(t,error)])
	},
	rMem(TSRMem,PropshRMem1,PropsRMem0,EtqhRMem0,EtqRMem1,CodRMem1),
	{
	/*
		RMem(0).props = RMem(1).props
	
		RMem(0).cod = "Apila_ind" || RMem(1).cod
		RMem(0).etq = RMem(1).etq + 1
	*/
		agrega([[apila_ind],CodRMem1],CodRMem0),
		EtqRMem0 is EtqRMem1 + 1
	}.
%RMem(+TS,+Propsh,-Props,+Etqh,-Etq,-Cod)
rMem(TSRMem,PropshRMem0,PropsRMem0,EtqhRMem0,EtqRMem0,CodRMem0) --> 
	% . 
	[(punto,_,_)],
	id(LexID,_,_),
	{
	/*	RMem(1).tsh = RMem(0).tsh
		%RMem(1).propsh = if(RMem(0).propsh.t == reg,
					if (existeCampo(RMem(0).propsh.campos,ID.lex),
						RMem(0).propsh.campos[ID.lex].tipo,
						<t:error>),
					<t:error>)
					
		RMem(1).etqh = RMem(0).etqh
	*/
		dameAtrib(PropshRMem0,t,T),
		(igual(T,rec,true) ->	(dameAtrib(PropshRMem0,campos,Campos),existeCampo(Campos,LexID,true) ->
									(dameCampo(Campos,LexID,Campo),dameAtrib(Campo,tipo,PropshRMem11),PropshRMem1=[(t,PropshRMem11)])
									; 
									PropshRMem1=[(t,error)])
								; PropshRMem1=[(t,error)])
	},	
	rMem(TSRMem,PropshRMem1,PropsRMem0,EtqhRMem0,EtqRMem1,CodRMem1),
	{
	/*
		RMem(0).props = RMem(1).props
		
		RMem(0).cod = "Apila_i(RMem(0).propsh.campos[ID.lex].desp)" || "Suma" ||RMem(1).cod
		RMem(0).etq = RMem(1).etq + 2
	*/
		dameAtrib(Campo,desp,Desp),
		agrega([[apila_i(Desp)],[suma],CodRMem1],CodRMem0),
		EtqRMem0 is EtqRMem1 + 2
	}.
%RMem(+TS,+Propsh,-Props,+Etqh,-Etq,-Cod)
rMem(TSRMem,PropshRMem0,PropsRMem0,EtqhRMem0,EtqRMem0,CodRMem0) --> 
	%[E0] 
	[(cap,_,_)],
/*
	E0.etqh = RMem(0).etqh
*/
	e0(TSRMem,TipoE0,_,_,EtqhRMem0,EtqE0,CodE0),
	[(ccierre,_,_)],
	{
	/*
		RMem(1).tsh = RMem(0).tsh
		RMem(1).propsh = if (RMem(0).propsh.t = array && E0.tipo = int,
					RMem(0).propsh.tbase,
					<t:error>) 

		RMem(1).etqh = E0.etq
	*/
		dameAtrib(PropshRMem0,t,T),igual(T,array,E1),igual(TipoE0,int,E2),
		(and([E1,E2],true) ->	dameAtrib(PropshRMem0,tbase,PropshRMem1)
								; PropshRMem1=[(t,error)])
	},
	rMem(TSRMem,PropshRMem1,PropsRMem0,EtqE0,EtqRMem1,CodRMem1),
	{
	/*
		RMem(0).props = RMem(1).props
	
		RMem(0).cod = E0.cod || "Apila (RMem(0).propsh.tbase.tam)" || "Mult" || "Suma" || RMem(1).cod
		RMem(0),etq = RMem(1).etq + 3
	*/
		dameAtrib(PropshRMem0,tbase,X),
		dameAtrib(X,tam,TamTbasePropshRMem0),
		agrega([CodE0,[apila_i(TamTbasePropshRMem0)],[mult],[suma],CodRMem1],CodRMem0),
		EtqRMem0 is EtqRMem1 + 3
	}.
%RMem(+TS,+Propsh,-Props,+Etqh,-Etq,-Cod)
rMem(_,PropshRMem,PropshRMem,EtqhRMem,EtqhRMem,CodRMem) --> 
	%lambda
	[],
	{
	/*
		RMem.props = RMem.propsh
	
		RMem.cod = ""
		RMem.etqh = RMem.etq
	*/
		CodRMem = []
	}.

	
%Acts(+Ts,+Nh,+Ret,-Error,+Etqh,-Etq,-Cod)
acts(TSActs,NhActs,RethActs,ErrActs,EtqhActs,EtqActs,CodActs) --> 
/*
	Act.nh = Acts.nh
	
	Act.ts = Acts.ts
	Act.reth = Acts.reth
	
	Act.etqh = Acts.etqh
*/
	act(TSActs,NhActs,RethActs,ErrAct,EtqhActs,EtqAct,CodAct),
/*	
	RActs.nh = Acts.nh

	RActs.reth = Acts.reth

	RActs.etqh = Act.etq
*/	
	rActs(TSActs,NhActs,RethActs,ErrRActs,EtqAct,EtqActs,CodRActs),
	{
	/*
		Acts.err = Act.err v RActs.err
	
		Acts.etq = RActs.etq
		Acts.cod = Act.cod || RActs.cod
	*/
		or([ErrAct,ErrRActs],ErrActs),
		
		agrega([CodAct,CodRActs],CodActs)
	}.
	
%RActs(+Ts,+Nh,+Reth,-Error,+Etqh,-Etq,-Cod)
rActs(TSRActs,NhRActs,RethRActs0,ErrRActs0,EtqhRActs0,EtqRActs0,CodRActs0) --> 
/*
	Act.nh = RActs(0).nh
	
	Act.ts = RActs(0).ts
	Act.reth = RActs(0).reth
	
	Act.etqh = RActs(0).etqh
*/
	act(TSRActs,NhRActs,RethRActs0,ErrAct,EtqhRActs0,EtqAct,CodAct),
/*
	RActs(1).nh = RActs(0).nh
	
	RActs(1).reth = RActs(0).reth
	RActs(1).ts = RActs(0).ts

	RActs(1).etqh = Act.etq
*/	
	rActs(TSRActs,NhRActs,RethRActs0,ErrRActs1,EtqAct,EtqRActs0,CodRActs1),
	{
	/*
		RActs(0).err = Act.err v RActs(1).err
		
		RActs(0).etq = RActs(1).etq
		RActs(0).cod = Act.cod || RActs(1).cod
	*/
		or([ErrAct,ErrRActs1],ErrRActs0),
		
		agrega([CodAct,CodRActs1],CodRActs0)
	}.
	
%RActs(+Ts,+Nh,+Reth,-Error,Etqh,Etq,Cod)
rActs(_,_,_,ErrRActs,EtqhRActs,EtqhRActs,CodRActs) -->
/*
	lambda
*/
	[],
	{
	/*
		RActs.etq = RActs.etqh
		RActs.cod = ""
	*/
		ErrRActs = false,
		
		CodRActs = []
	}.	

%act(+TS,+Nh,+Reth,-Error,+Etqh,-Etq,-Cod)
act(TSAct,_,RethAct,ErrAct,EtqhAct,EtqAct,CodAct) -->
/*
	IIf.reth = Act.reth
	IIf.ts = Act.ts
	
	IIf.etqh = Act.etqh
*/	iIf(TSAct,RethAct,ErrAct,EtqhAct,EtqAct,CodAct),
	% ;
	[(pyc,_,_)].
/*	
	Act.err = IIf.err

	Act.cod = IIf.cod
	Act.etq = IIf.etq
*/

%act(+TS,+Nh,+Reth,-Error,+Etqh,-Etq,-Cod)	
act(TSAct,_,RethAct,ErrAct,EtqhAct,EtqAct,CodAct) -->
/*
	IWhile.reth = Act.reth
	IWhile.ts = Act.ts
	
	IWhile.etqh = Act.etqh
*/	
	iWhile(TSAct,RethAct,ErrAct,EtqhAct,EtqAct,CodAct),
	% ;
	[(pyc,_,_)].
/*
	Act.err = IWhile.err
	
	Act.cod = IWhile.cod
	Act.etq = IWhile.etq
*/
%act(+TS,+Nh,+Reth,-Error,+Etqh,-Etq,-Cod)	
act(TSAct,_,_,ErrAct,EtqhAct,EtqAct,CodAct) -->
/*
	INew.ts = Act.ts
	
	INew.etqh = Act.etqh
*/
	iNew(TSAct,_,ErrAct,EtqhAct,EtqAct,CodAct),
	% ;
	[(pyc,_,_)].
/*
	Act.err = INew.err

	Act.cod = INew.cod
	Act.etq = INew.etq
*/
%act(+TS,+Nh,+Reth,-Error,+Etqh,-Etq,-Cod)	
act(TSAct,_,_,ErrAct,EtqhAct,EtqAct,CodAct) -->
/*
	IDel.ts = Act.ts
	
	IDel.etqh = Act.etqh
*/	
	iDel(TSAct,_,ErrAct,EtqhAct,EtqAct,CodAct),
	% ;
	[(pyc,_,_)].
/*
	Act.err = IDel.err	

	Act.cod = IDel.cod
	Act.etq = IDel.etq
*/

%act(+TS,+Nh,+Reth,-Error,+Etqh,-Etq,-Cod)	
act(TSAct,_,_,ErrAct,EtqhAct,EtqAct,CodAct) -->
	{
	/*
		E0.ts = Act.ts
	
		E0.parh = false
		E0.etqh = Act.etqh
	*/
		ParhE0 = false
	},
	e0(TSAct,TipoE0,_,ParhE0,EtqhAct,EtqE0,CodE0),
	% ;
	[(pyc,_,_)],
	{
	/*
		Act.err = E0.tipo.t == error
		
		Act.cod = E0.cod || "Elimina_cima"
		Act.etq = E0.etq + 1
	*/
		igual(TipoE0,error,ErrAct),
		
		EtqAct is EtqE0 + 1,
		agrega([CodE0,[elimina_cima]],CodAct)
	}.

%act(+TS,+Nh,+Reth,-Error,+Etqh,-Etq,-Cod)	
act(TSAct,_,RethAct,ErrAct,EtqhAct,EtqAct,CodAct) -->
	{
	/*
		E0.ts = Act.ts

		E0.parh = false
		E0.etqh = Act.etqh
	*/
		ParhE0 = false	
	},
	%return 
	[(retorno,_,_)],
	e0(TSAct,TipoE0,_,ParhE0,EtqhAct,EtqE0,CodE0),
	% ; 
	[(pyc,_,_)],
	{
	/*
		Act.err = ((Act.reth == error) v (E0.tipo == Error) v (Act.reth != E0.tipo))		
		
		Act.cod = E0.cod || Epilogo(Acts.nh) || "Ir_ind"
		Act.etq = E0.etq + LongEpilogo() + 1
	*/
		igual(RethAct,error,RetPpal),
		igual(TipoE0,error,ErrTipo),
		distinto(RethAct,TipoE0,DisRet),
		or([RetPpal,ErrTipo,DisRet],ErrAct),
		
		epilogo(Epilogo),
		agrega([CodE0,Epilogo,[ir_ind]],CodAct),
		
		%TODO: CUIDADO!!! Hay dos epilogos, uno en el return, y otro en actsFun. Decidir con cual nos quedamos !!!
		longEpilogo(LongEpilogo),
		EtqAct is EtqE0 + LongEpilogo + 1	
	}.

%IIF(+TS,+Reth,-Error,+Etqh,-Etq,-Cod)	
iIf(TSIf,RethIf,ErrIf,EtqhIIf,EtqIIf,CodIIf) -->
	% if
	[(iniIf,_,_)],
	{
	/*
		E0.ts = IIf.ts

		E0.parh = false
		E0.etqh = IIf.etqh
	*/
		ParhE0 = false	 
	},
	e0(TSIf,TipoE0,_,ParhE0,EtqhIIf,EtqE0,CodE0),
	% then 
	[(then,_,_)],
	{
	/*
		Acts.reth  = IIf.reth
		Acts.ts = IIf.ts	

		Acts.etqh = E0.etq + 1
	*/
		EtqhActs is EtqE0 + 1
	},
	acts(TSIf,_,RethIIf,ErrActs,EtqhActs,EtqActs,CodActs), %TODO: ¿QUE PASA CON NH?
	{
	/*
		PElse.reth = IIf.reth
		PElse.ts = IIf.ts

		PElse.etqh = Acts.etq + 1
	*/
		EtqActs1 is EtqActs + 1
	},
	pElse(TSIf,RethIf,ErrPElse,EtqActs1,EtqIIf1,CodPElse),
	{
	/*
		IIf.err = Acts.err v PElse.err v E0.tipo.t != int			
	
		IIf.cod = E0.cod || "Ir_f (Acts.etq + 1)" || Acts.cod || 
			  "Ir_a (PElse.etq)" || PElse.cod
		IIf.etq = PElse.etq
	*/
		distinto(TipoE0,int,ErrTipo),
		or([ErrActs,ErrPElse,ErrTipo],ErrIf),
		
		agrega([CodE0,[ir_f(EtqActs1)],CodActs,[ir_a(EtqIIf1)],CodPElse],CodIIf)
	}.

%PElse(+TS,+Reth,-Error,+Etqh,-Etq,-Cod)
pElse(TSElse,RethElse,ErrElse,EtqhPElse,EtqPElse,CodPElse) --> 
	% else 
	[(relse,_,_)],	
/*	
	Acts.reth = PElse.reth
	Acts.ts = PElse.ts	

	Acts.etqh = PElse.etqh
*/
	acts(TSElse,_,RethElse,ErrElse,EtqhPElse,EtqPElse,CodPElse), 
	% fi
	[(finIf,_,_)].
/*	
	PElse.err = Acts.err
	
	PElse.cod = Acts.cod
	PElse.etq = Acts.etq
*/	
	
%PElse(+TS,+Reth,-Error,+Etqh,-Etq,-Cod)		
pElse(TSElse,RethElse,ErrElse0,EtqhPElse0,EtqPElse0,CodPElse0) -->
	% elsif 
	[(relsif,_,_)],		
	{
	/*
		E0.ts = PElse(0).ts

		E0.parh = false
		E0.etqh = PElse(0).etqh
	*/
		ParhE0 = false	
	},
	e0(TSElse,TipoE0,_,ParhE0,EtqhPElse0,EtqE0,CodE0),
	% then 
	[(then,_,_)],	
	{
	/*
		Acts.reth = PEls(0).reth
		Acts.ts = PElse(0).ts

		Acts.etqh = E0.etq + 1
	*/
		EtqhActs is EtqE0 + 1		
	},
	acts(TSElse,_,RethElse,ErrActs,EtqhActs,EtqActs,CodActs),
	{
	/*
		PElse(1).reth = PElse(0).reth
		PElse(1).ts = PElse(0).ts

		PElse(1).etqh = Acts.etq + 1
	*/
		EtqhPElse1 is EtqActs + 1	
	},
	pElse(TSElse,RethElse,ErrElse1,EtqhPElse1,EtqPElse0,CodPElse1),
	{
	/*
		PElse(0).err = Acts.err v PElse(1).err v E0.tipo.t != int
	
		PElse(0).cod = E0.cod || "Ir_f (Acts.etq + 1)" || Acts.cod || "Ir_a (PElse(1).etq)" || PElse(1).cod
		PElse(0).etq = PElse(1).etq
	*/
		distinto(TipotE0,int,ErrTipo),
		or([ErrActs,ErrPElse,ErrTipo],ErrIf),
		
		Parchea is EtqActs + 1,
		agrega([CodE0,[ir_f(Parchea)],CodActs,[ir_a(EtqPElse0)],CodPElse1],CodPElse0)
	}.
%PElse(+TS,+Reth,-Error,+Etqh,-Etq,-Cod)
pElse(_,_,ErrElse,EtqhPElse,EtqhPElse,CodPElse) -->
	% fi
	[(finIf,_,_)],	
	{	
	/*
		PElse.err = False	
		
		PElse.etq = PElse.etqh
		PElse.cod = ""
	*/
		ErrElse = false,
		
		CodPElse = []
	}.

%IWhile(+TS,+Reth,-Error,+Etqh,-Etq,-Cod)	
iWhile(TSWhile,RethWhile,ErrWhile,EtqhIWhile,EtqIWhile,CodIWhile) --> 
	% while 
	[(iniWhile,_,_)],			
	{
	/*
		E0.ts = IWhile.ts
	
		E0.parh = false
		E0.etqh = IWhile.etqh
	*/
		ParhE0 = false	
	},
	e0(TSWhile,TipoE0,_,ParhE0,EtqhIWhile,EtqE0,CodE0),
	% do 
	[(hacer,_,_)],		
	{
	/*
		Acts.ts = IWhile.ts	
		Acts.reth = IWhile.reth
	
		Acts.etqh = E0.etq + 1
	*/
		EtqhActs is EtqE0 + 1
	},
	acts(TSWhile,_,RethWhile,ErrActs,EtqhActs,EtqActs,CodActs),
	% endwhile
	[(finWhile,_,_)],				
	{
	/*
		IWhile.err = Acts.err v E0.tipo.t != int
	
		IWhile.cod = E0.cod || "Ir_f (Acts.etq + 1)" || Acts.cod || "Ir_a (IWhile.etqh)"
		IWhile.etq = Acts.etq + 1
	*/		
		distinto(TipoE0,int,ErrTipo),
		or([ErrActs,ErrTipo],ErrIWhile),
		
		Parchea is EtqActs + 1,
		agrega([CodE0,[ir_f(Parchea)],CodActs,[ir_a(EtqhIWhile)]],CodIWhile),
		EtqIWhile is EtqActs + 1
	}.

%INew(+TS,+Reth,-Error,+Etqh,-Etq,-Cod)
iNew(TSNew,_,ErrNew,EtqhNew,EtqNew,CodNew) --> 
	% alloc 
	[(reservaMem,_,_)],				
/*
	Mem.etqh = INew.etqh
*/
	mem(TSNew,PropsMem,EtqhNew,EtqMem,CodMem),
	{
	/*
		INew.err = (Mem.props.t != "puntero")
		
		INew.cod = Mem.cod || "New (Mem.props.tam)" || "Desapila_ind"
		INew.etq = Mem.etq + 2
	*/
		dameAtrib(PropsMem,t,TipoMem),
		distinto(TipoMem,puntero,ErrNew),
		
		dameAtrib(PropsMem,tam,TamPropsMem),
		agrega([CodMem,[new(TamPropsMem)],[desapila_ind]],CodNew),
		EtqNew is EtqMem + 2
	}.

%IDel(+TS,+Reth,-Error,+Etqh,-Etq,-Cod)
iDel(TSDel,_,ErrMem,EtqhDel,EtqDel,CodDel) --> 
	%free 
	[(liberaMem,_,_)],				
/*
	Mem.etqh = IDel.etqh
*/
	mem(TSDel,PropsMem,EtqhDel,EtqMem,CodMem),
	{
	/*
		IDel.err = (Mem.props.t != "puntero")		
		
		IDel.cod = Mem.cod || "Del (Mem.props.tam)"
		IDel.etq = Mem.etq + 1
	*/
		%TODO: Mem.props.t
		distinto(TipoMem,puntero,ErrDel)
	}.

%E0(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)
e0(TSE0,TipoE0,ModoE0,_,EtqhE0,EtqE0,CodE0) --> 
	% out 
	[(salida,_,_)],				
	{
	/*
		E1.ts = E0.ts
	
		E1.parh = false
		E1.etqh = E0.etqh
	*/		
		ParhE1 is false
	},
	e1(TSE0,TipoE0,ModoE0,ParhE1,EtqhE0,EtqE1,CodE1),
	{
	/*	
		E0.modo = E1.modo
		E0.tipo = E1.tipo
	
		E0.cod = E1.cod || "Escribir"
		E0.etq = E1.etq + 1
	*/
		agrega([CodE1,[escribir]],CodE0),
		EtqE0 is EtqE1 + 1
	}.

%E0(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)
e0(TSE0,TipoE0,ModoE0,_,EtqhE0,EtqE0,CodE0) --> 
	% in
	[(entrada,_,_)],				 
/*
	Mem.ts = E0.ts

	Mem.etqh = E0.etqh
*/	
	mem(TSE0,PropsMem,EtqhE0,EtqMem,CodMem),
	{
	/*
		E0.modo = "var"
		E0.tipo = Mem.props.t
	
		TODO E0.cod = if(Mem.props.t == Real,
				Mem.cod || "Leer Real",
				Mem.cod || "Leer Int")
		E0.etq = Mem.etq + 1
	*/
		ModoE0=var,
		dameAtrib(PropsMem,t,TipoE0),
		(igual(TipoE0,real,true) ->
			agrega([CodMem,[leer_real]],CodE0)
			; agrega([CodMem,[leer_int]],CodE0)),
		EtqE0 is EtqMem + 1
	}.
%E0(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)
e0(TSE0,TipoE0,ModoE0,ParhE0,EtqhE0,EtqE0,CodE0) --> 
/*
	E1.ts = E0.ts
	
	E1.parh = E0.parh
	E1.etqh = E0.etqh
*/
	e1(TSE0,TipoE0,ModoE0,ParhE0,EtqhE0,EtqE0,CodE0).
/*	
	E0.modo = E1.modo
	E0.tipo = E1.tipo	
	
	E0.etq = E1.etq
	E0.cod = E1.cod
*/

%E1(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)
e1(TSE1,TipoE1,ModoE1,_,EtqhE1,EtqE1,CodE1) --> 
/*
	Mem.etqh = E1.etqh	
*/
	mem(TSE1,PropsMem,EtqhE1,EtqMem,CodMem,IDMem),
	{
	/*
		RE1.ts = E1.ts
		RE1.tipoh = Mem.props.t
		RE1.modoh = "var"
	
		RE1.parh = false
		RE1.codh = Mem.cod
		RE1.propsh = Mem.props
		RE1.etqh = Mem.etq
	*/
		ParhRE1 = false,
		dameAtrib(PropsMem,t,TipohRE1),
		ModohRE1=var
	},

	rE1(TSE1,TipohRE1,ModohRE1,TipoE1,ModoE1,ParhRE1,CodMem,PropsMem,EtqMem,EtqE1,CodE1).
/*	
	E1.tipo = RE1.tipo	
	E1.modo = RE1.modo
	
	E1.cod = RE1.cod
	E1.etq = RE1.etq
*/
%E1(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)
e1(TSE1,TipoE1,ModoE1,ParhE1,EtqhE1,EtqE1,CodE1) --> 
/*
	E5Otro.ts = E1.ts
	
	E5Otro.parh = E1.parh
	E5Otro.etqh = E1.etqh 
*/
	e5Otro(TSE1,TipoE5,ModoE5,ParhE1,EtqhE1,EtqE5Otro,CodE5Otro),
/*
	RE4.ts = E1.ts
	RE4.tipoh = E5Otro.tipo
	RE4.modoh = E5Otro.modo
	
	RE4.parh = E1.parh
	RE4.codh = E5Otro.cod
	RE4.etqh = E5Otro.etq
*/
	rE4(TSE1,TipoE5,ModoE5,TipoRE4,ModoRE4,ParhE1,CodE5Otro,EtqE5Otro,EtqRE4,CodRE4),
/*
	RE3.ts = E1.ts
	RE3.tipoh = RE4.tipo
	RE3.modoh = RE4.modo
	
	RE3.parh = E1.parh
	RE3.etqh = RE4.etq
	RE3.codh = RE4.cod
*/
	rE3(TSE1,TipoRE4,ModoRE4,TipoRE3,ModoRE3,ParhE1,CodRE4,EtqRE4,EtqRE3,CodRE3),
/*
	RE2.ts = E1.ts
	RE2.tipoh = RE3.tipo
	RE2.modoh = RE3.modo
	
	RE2.parh = E1.parh
	RE2.etqh = RE3.etq
	RE2.codh = RE3.cod
*/
	rE2(TSE1,TipoRE3,ModoRE3,TipoE1,ModoE1,ParhE1,CodRE3,EtqRE3,EtqE1,CodE1).
/*
	E1.modo = RE2.modo
	E1.tipo = RE2.tipo	
	
	E1.etq = RE2.etq
	E1.cod = RE2.cod
*/
%RE1(+TS,+Tipoh,+Modoh,-Tipo,-Modo,+Parh,+Codh,+Propsh,+Etqh,-Etq,-Cod).
rE1(TSRE1,TipohRE1,ModohRE1,TipoRE1,ModohRE1,ParhRE1,CodhRE1,PropshRE1,EtqhRE1,EtqRE1,CodRE1) --> 
	% = 
	[(asig,_,_)],				
/*
	E1.ts = RE1.ts
	
	E1.parh = RE1.parh
	
	E1.etqh = RE1.etqh
*/
	e1(TSRE1,TipoE1,ModoE1,ParhRE1,EtqhRE1,EtqE1,CodE1),		
	{	
	/*	
		RE1.tipo = if((compatibles(RE1.tipoh, E1.tipo, RE1.ts) && RE1.tipoh != error),
							E1.tipo,
							Error) 
		%TODO: compatibles
		RE1.modo = RE1.modoh		

		TODO		
		RE1.cod = if ((RE1.propsh.t == Real v RE1.propsh.t == Int),
							if((RE1.propsh.t == Real) && (E1.tipo == Int),
								RE1.codh || E1.cod || "ConvReal" || "Copia_cima" || Desapila_ind,
								RE1.codh || E1.cod || "Copia_cima" || Desapila_ind)
							RE1.codh || E1.cod || mueve(Mem.props.tam))			
		TODO
		RE1.etq = if ((RE1.propsh.t == Real v RE1.propsh.t == Int),
							if((RE1.propsh.t == Real) && (E1.tipo == Int),
								E1.etq + 3, 
								E1.etq + 2)
							E1.etq + 2)	
	*/		
		compatibles(TSRE1,TipohRE1,TipoE1,A1),distinto(TipohRE1,error,A2),and([A1,A2],true)->(
			TipoRE1=TipoE1
			;
			TipoRE1=error),
		dameAtrib(PropshRE1,t,T),

		igual(T,real,A3),igual(T,int,A4),
		(or([A3,A4],true)->	(igual(T,real,A7),
							 igual(TipoE1,int,A8),
							 (and([A7,A8],true)->
								(agrega([CodhRE1,CodE1,[convreal],[desapila_ind]],CodRE1),
								 EtqRE1 is EtqE1 + 3)
								;			
								(agrega([CodhRE1,CodE1,[desapila_ind]],CodRE1),
								 EtqRE1 is EtqE1 + 2))
							)
							;
							(dameAtrib(PropsMem,tam,Tam),
							 agrega([CodhRE1,CodE1,[mueve(Tam)]],CodRE1),
							 EtqRE1 is EtqE1 + 1
							))
	}.
%RE1(+TS,+Tipoh,+Modoh,-Tipo,-Modo,+Parh,+Codh,+Propsh,+Etqh,-Etq,-Cod).
rE1(TSRE1,TipohRE1,ModohRE1,TipoRE1,ModoRE1,ParhRE1,CodhRE1,_,EtqhRE1,EtqRE1,CodRE1) --> 
/*
	RE4.ts = RE1.ts
	RE4.tipoh = RE1.tipoh
	RE4.modoh = RE1.modoh

	RE4.parh = RE1.parh
	RE4.etqh = RE1.etqh
	RE4.codh = RE1.codh
*/
	rE4(TSRE1,TipohRE1,ModohRE1,TipoRE4,ModoRE4,ParhRE1,CodhRE1,EtqhRE1,EtqRE4,CodRE4),
/*
	RE3.ts = RE1.ts
	RE3.tipoh = RE4.tipo
	RE3.modoh = RE4.modo
	
	RE3.parh = RE1.parh
	RE3.etqh = RE4.etq
	RE3.codh = RE4.cod
*/
	rE3(TSRE1,TipoRE4,ModoRE4,TipoRE3,ModoRE3,ParhRE1,CodRE4,EtqRE4,EtqRE3,CodRE3),
/*
	RE2.ts = RE1.ts
	RE2.tipoh = RE3.tipo
	RE2.modoh = RE3.modo

	RE2.parh = RE1.parh
	RE2.etqh = RE3.etq
	RE2.codh = RE3.cod
*/
	rE2(TSRE1,TipoRE3,ModoRE3,TipoRE1,ModoRE1,ParhRE1,CodRE3,EtqRE3,EtqRE1,CodRE1).
/*
	RE1.tipo = RE2.tipo
	RE1.modo = RE2.modo

	RE1.etq = RE2.etq
	RE1.cod = RE2.cod
*/		
%RE2(+TS,+Tipoh,+Modoh,-Tipo,-Modo,+Parh,+Codh,+Etqh,-Etq,-Cod).
rE2(TSRE2,TipohRE2,_,TipoRE2,ModoRE2,ParhRE2,CodhRE2,EtqhRE2,EtqRE2,CodRE2) --> 
/*
	Op2.etqh = RE2.etqh
*/
	op2(Opop2,EtqhRE2,EtqOp2,CodOp2),
/*
	E3.ts = RE2.ts

	E3.parh = RE2.parh
	E3.etqh = Op2.etq
*/
	e3(TSRE2,TipoE3,_,ParhRE2,EtqOp2,EtqE3,CodE3),
	{
	/*
		RE2.tipo = tipoDeB(Op2.op, RE2.tipoh, E3.tipo)
		RE2.modo = "val"
		TODO: tipoDeB
		
			TODO RE2.cod = if(RE2.tipoh == Int) && (E3.tipo == Real),
						RE2.codh || "ConvAReal" || E3.cod || Op2.cod,
						if((RE2.tipoh == Real) && (E3.tipo == Int),
							RE2.codh || E3.cod || "ConvAReal" || Op2.cod,
							RE2.codh || E3.cod || Op2.cod))
			TODO RE2.etq = if(RE2.tipoh == In && E3.tipo == Real,
						E3.etq + 1,
						if(RE2.tipoh == Real && E3.tipo == Int,
							E3.etq + 1,
							E3.etq))
	*/
		(igual(TipohRE2,int,A1),igual(TipoE3,real,A2),and([A1,A2],true)->
			(agrega([CodhRE2,[convreal],CodE3,CodOp2],CodRE2),
			 EtqRE2 is EtqE3 + 1
			)
			;
			(igual(TipohRE2,real,A1),igual(TipoE3,int,A2),and([A1,A2],true)->
				(agrega([CodhRE2,CodE3,[convreal],CodOp2],CodRE2),
				 EtqRE2 is EtqE3 + 1
				)
				;
				(agrega([CodhRE2,CodE3,CodOp2],CodRE2),
				 EtqRE2 is EtqE3
				))),
		tipoDe(TipohRE2,TipoE3,Opop2,TipoRE2),
		ModoRE2=val
	}.
	
%RE2(+TS,+Tipoh,+Modoh,-Tipo,-Modo,+Parh,+Codh,+Etqh,-Etq,-Cod).
rE2(_,TipohRE2,ModohRE2,TipohRE2,ModohRE2,_,CodhRE2,EtqhRE2,EtqhRE2,CodhRE2) --> 
	%Lambda
	[].
/*
	RE2.tipo = RE2.tipoh
	RE2.modo = RE2.modoh
	
	RE2.etq = RE2.etqh
	RE2.cod = RE2.codh
*/

%E3(+TS,-Tipo,-Modo,-Parh,+Etqh,-Etq,-Cod)
e3(TSE3,TipoE3,ModoE3,ParhE3,EtqhE3,EtqE3,CodE3) --> 
/*
	Mem.etqh = E3.etqh
*/
	mem(TSE3,PropsMem,EtqhE3,EtqMem,CodMem),
	{ 
	/*
		RE4.ts = E3.ts
		TODO: RE4.tipoh = Mem.props.t	
		RE4.modoh = "var"
		
		RE4.parh = E3.parh
		RE4.etqh = Mem.etq
		RE4.codh = Mem.cod
	*/
		ModohRE4 = var,
		dameAtrib(PropsMem,t,PropsTMem),
		agrega([CodMem,[apila_ind]],CodMem1),
		EtqMem1 is EtqMem + 1
		
	},
	rE4(TSE3,PropsTMem,ModohRE4,TipoRE4,ModoRE4,ParhE3,CodMem1,EtqMem1,EtqRE4,CodRE4),
/*
	RE3.ts = E3.ts
	RE3.tipoh = RE4.tipo
	RE3.modoh = RE4.modo

	RE3.parh = E3.parh
	RE3.etqh = RE4.etq
	RE3.codh = RE4.cod
*/
	rE3(TSE3,TipoRE4,ModoRE4,TipoE3,ModoE3,ParhE3,CodRE4,EtqRE4,EtqE3,CodE3).
/*
	E3.tipo = RE3.tipo
	E3.modo = RE3.modo
	
	E3.etq = RE3.etq
	E3.cod = RE3.cod
*/
	
	
%E3(+TS,-Tipo,-Modo,-Parh,+Etqh,-Etq,-Cod)
e3(TSE3,TipoE3,ModoE3,ParhE3,EtqhE3,EtqE3,CodE3) -->
/*
	E5Otro.ts = E3.ts
	
	E5Otro.parh = E3.parh
	E5Otro.etqh = E3.etq
*/ 
	e5Otro(TSE3,TipoE5Otro,ModoE5Otro,ParhE3,EtqhE3,EtqE5Otro,CodE5Otro),
/*
	RE4.ts = E3.ts
	RE4.tipoh = E5Otro.tipo
	RE4.modoh = E5Otro.modo
	
	RE4.parh = E3.parh
	RE4.etqh = E5Otro.etq
	RE4.codh = E5Otro.cod
*/
	rE4(TSE3,TipoE5Otro,ModoE5Otro,TipoRE4,ModoRE4,ParhE3,CodE5Otro,EtqE5Otro,EtqRE4,CodRE4),
/*
	RE3.ts = E3.ts
	RE3.tipoh = RE4.tipo
	RE3.modoh = RE4.modo

	RE3.parh = E3.parh
	RE3.etqh = RE4.etq
	RE3.codh = RE4.cod
*/
	rE3(TSE3,TipoRE4,ModoRE4,TipoE3,ModoE3,ParhE3,CodRE4,EtqRE4,EtqE3,CodE3).
/*
	E3.tipo = RE3.tipo
	E3.modo = RE3.modo

	E3.etq = RE3.etq
	E3.cod = RE3.cod
*/	
	
%RE3(+TS,+Tipoh,+Modoh,-Tipo,-Modo,+Parh,+Codh,+Etqh,-Etq,-Cod).	
rE3(TSRE3,TipohRE30,_,TipoRE30,ModoRE3,ParhRE30,CodhRE30,EtqhRE30,EtqRE30,CodRE30) --> 
/*
	Op3.etqh = RE3(0).etqh
*/
	op3(OpOp3,EtqhRE30,EtqOp3,CodOp3),
/*
	E4.ts = RE3(0).ts
	
	E4.parh = RE3(0).parh
	E4.etqh = Op3.etq
*/
	e4(TSRE3,TipoE4,_,ParhRE30,EtqOp3,EtqE4,CodE4),
	{
	/*
		RE3(1).ts = RE3(0).ts
		RE3(1).tipoh = tipoDeB(Op3.op, RE3(0).tipoh, E4.tipo)
		
		RE3(1).parh = RE3(0).parh
		RE3(1).etqh = E4.etq
		RE3(1).codh = if(Op3.op == LogicO,
				RE3(0).codh || E4.cod || Op3.cod,
				if (RE3(0).tipoh == Int && E4.tipo == Real,
					RE3(0).codh || "ConvReal" || E4.cod || Op3.cod,
				if(RE(0).tipoh == Real && E4.tipo == Int,
					RE3(0).codh || E4.cod || "ConvReal" || Op3.cod,
					RE3(0).codh || E4.cod || Op3.cod )))
	*/		
		(igual(OpOp3,logico,true)-> 
			(agrega([CodhRE30,CodE4,CodOp3],CodhRE31))
			;
			igual(TipohRE30,int,A1), 
			 igual(TipoE4,real,A2), 
			 (and([A1,A2],true)-> 	(agrega([CodhRE30,[convreal],CodE4,CodOp3],CodhRE31))
									;
									(igual(TipohRE30,real,A1), 
									 igual(TipoE4,int,A2), 
									 and([A1,A2],true)-> 
										(agrega([CodhRE30,CodE4,[convreal],CodOp3],CodhRE31))
										;
										agrega([CodhRE30,CodE4,CodOp3],CodhRE31)))),
		tipoDe(TipohRE30,TipoE4,OpOp3,TipohRE31)
	},
	rE3(TSRE3,TipohRE31,_,TipoRE30,_,ParhRE30,CodhRE31,EtqE4,EtqRE31,CodRE30),
	{
	/*
		RE3(0).tipo = RE3(1).tipo
		RE3(0).modo = "val"	
		
		RE3(0).etq = if(Op3.op == LogicO,
			RE3(1).etq,
			if (RE3(0).tipoh == Int && E4.tipo == Real,
				RE3(1).etq + 1,
			if(RE(0).tipoh == Real && E4.tipo == Int,
				RE3(1).etq + 1,
				RE3(1).etq )))
		RE3(0).cod = RE3(1).cod
	*/
		ModoRE3 = val,
		igual(OpOp3,logico,true)->
			EtqRE30 is EtqRE31
			;
			(igual(TipohRE30,int,A1),igual(TipoE4,real,A2),and([A1,A2],true)->
				EtqRE30 is EtqRE31 + 1
				;
				(igual(TipohRE30,real,A1),igual(TipoE4,int,A2),and([A1,A2],true)->
					EtqRE30 is EtqRE31 + 1
					;
					EtqRE30 is EtqRE31
				)
			)
	}.
	
%RE3(+TS,+Tipoh,+Modoh,-Tipo,-Modo,+Parh,+Codh,+Etqh,-Etq,-Cod).	
rE3(_,TipohRE3,ModohRE3,TipohRE3,ModohRE3,_,CodhRE3,EtqhRE3,EtqhRE3,CodhRE3) --> 
	% Lambda
	[].
/*
	RE3.tipo = RE3.tipoh
	RE3.modo = RE3.modoh

	RE3.etq = RE3.etqh
	RE3.cod = RE3.codh
*/

%E4(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)
e4(TSE4,TipoE4,ModoE4,ParhE4,EtqhE4,EtqE4,CodE4) -->
/*
	Mem.etqh = E4.etqh
*/
	mem(TSE4,PropsMem,EtqhE4,EtqMem,CodMem),
	{
	/*
		RE4.ts = E4.ts
		TODO: RE4.tipoh = Mem.props.t
		RE4.modoh = "var"
		
		RE4.parh = E4.parh
		RE4.etqh = Mem.etq
		RE4.codh = Mem.cod
	*/
		ModohRE4 = var
	},
	rE4(TSE4,PropsMem,ModohRE4,TipoE4,ModoE4,ParhE4,CodMem,EtqMem,EtqE4,CodE4).
/*
	E4.tipo = RE4.tipo
	E4.modo = RE4.modo

	E4.etq = RE4.etq
	E4.cod = RE4.cod
*/
%E4(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)
e4(TSE4,TipoE4,ModoE4,ParhE4,EtqhE4,EtqE4,CodE4) -->
/*
	E5Otro.ts = E4.ts
	
	E5Otro.parh = E4.parh
	E5Otro.etqh = E4.etqh
*/
	e5Otro(TSE4,TipoE5Otro,ModoE5Otro,ParhE4,EtqhE4,EtqE5Otro,CodE5Otro),
/*
	RE4.ts = E4.ts
	RE4.tipoh = E5Otro.tipo
	RE4.modoh = E5Otro.modo
	
	RE4.parh = E4.parh
	RE4.etqh = E5Otro.etq
	RE4.codh = E5Otro.cod
*/
	rE4(TSE4,TipoE5Otro,ModoE5Otro,TipoE4,ModoE4,ParhE4,CodE5Otro,EtqE5Otro,EtqE4,CodE4).
/*
	E4.tipo = RE4.tipo
	E4.modo = RE4.modo

	E4.etq = RE4.etq
	E4.cod = RE4.cod
*/


%RE4(+TS,+Tipoh,+Modoh,-Tipo,-Modo,+Parh,+Codh,+Etqh,-Etq,-Cod).	
rE4(TSRE4,TipohRE40,_,TipoRE40,ModoRE40,ParhRE40,CodhRE4,EtqhRE40,EtqRE40,CodRE40) --> 
/*
	Op4.etqh = RE4(0).etqh
*/
	op4(OpOp4,EtqhRE40,EtqOp4,CodOp4),
/*
	E5.ts = RE4(0).ts	
	E5.parh = RE4(0).parh
	E5.etqh = Op4.etq
*/
	e5(TSRE4,TipoE5,_,ParhRE40,EtqOp4,EtqE5,CodE5),
	{
	/*
		RE4(1).ts = RE4(0).ts
		TODO: RE4(1).tipoh = tipoDeB(Op4.op, RE4(0).tipoh, E5.tipo)
		
		RE4(1).parh = RE4(0).parh
		RE4(1).etqh = E5.etq
		RE4(1).codh = if (Op4.op != "DivisionReal" && Op4.op != "Multiplicacion",
			RE4(0).codh || E5.cod || Op4.cod,
			if(Re4(0).tipoh=="Int" && E5.tipo == "Real",
				RE4(0).codh || "ConvReal" || E5.cod || Op4.cod,
			if (RE4(0).tipoh=="Real" && E5.tipo == "Int",
				RE4(0).codh || E5.cod || "ConvReal" || Op4.cod,
			if (RE4(0).tipoh== E5.tipo,
				if (Op4.cod=="Div",
					RE4(0).codh || E5.cod || "Div",
					RE4(0).codh || E5.cod || Op4.cod)))))
	*/
		tipoDe(TipohRE40,TipoE5,OpOp4,TipohRE41),
		distinto(OpOp4,divisionReal,A1),
		distinto(OpOp4,multiplicacion,A2),
		(and([A1,A2],true) ->
			agrega([CodhRE4,CodE5,CodOp4],CodhRE41)
			;
			(igual(TipohRE40,int,A3),
			 igual(TipoE5,real,A4),
			 (and([A3,A4],true) ->
				agrega([CodhRE4,[convReal],CodE5,CodOp4],CodhRE41)
				;
				(igual(TipohRE40,real,A5),
				 igual(TipoE5,int,A6),
				 (and([A3,A4],true) ->
					agrega([CodhRE4,CodE5,[convReal],CodOp4],CodhRE41)
					;
					(igual(TipohRE40,TipoE5,true)->
						(igual(CodOp4,div,true)->
							(agrega([CodhRE4,CodE5,div],CodhRE41)
							 ;
							 agrega([CodhRE4,CodE5,div],CodhRE41)
							)
						)
					)
					;
					agrega([CodhRE4,CodE5,div],CodhRE41)
				 )
				)
			 )
			)
		)
	},
	rE4(TSRE4,TipohRE41,_,TipoRE40,_,ParhRE40,CodhRE41,EtqE5,EtqRE41,CodRE40),
	{
	/*
		RE4(0).tipo = RE4(1).tipo
		RE4(0).modo = "val"

		RE4(0).etq = if (Op4.op != "DivisionReal" && Op4.op != "Multiplicacion",
			RE4(1).etq,
			if(Re4(0).tipoh=="Int" && E5.tipo == "Real",
				RE4(1).etq + 1,
			if (RE4(0).tipoh=="Real" && E5.tipo == "Int",
				RE4(1).etq + 1,
			if (RE4(0).tipoh== E5.tipo,
				RE4(1).etq ))))
		RE4(0).cod = RE4(1).cod
	*/
		ModoRE40=val,
		distinto(OpOp4,divisionReal,A1),
		distinto(OpOp4,multiplicacion,A2),
		(and([A1,A2],true)->
			EtqRE40 is EtqRE41
			;
			(igual(TipohRE40,int,A3),
			 igual(TipoE5,real,A4),
			 (and([A3,A4],true) ->
				EtqRE40 is EtqRE41+1
				;
				(igual(TipohRE40,real,A5),
				 igual(TipoE5,int,A6),
				 (and([A3,A4],true)->
					EtqRE40 is EtqRE41+1
					;
					(igual(TipohRE40,TipoE5,true)->
						EtqRE40 is EtqRE41+1
						;
						EtqRE40 is EtqRE41
					)
				 )
				)
			 )
			)
		)
	}.
	
%RE4(+TS,+Tipoh,+Modoh,-Tipo,-Modo,+Parh,+Codh,+Etqh,-Etq,-Cod)	
rE4(_,TipohRE4,ModohRE4,TipohRE4,ModohRE4,_,CodhRE4,EtqhRE4,EtqhRE4,CodhRE4) --> 
	% Lambda
	[].
/*
	RE4.tipo = RE4.tipoh
    	RE4.modo = RE4.modoh
    	
	RE4.etq = RE4.etqh
	RE4.cod = RE4.codh
*/

%E5(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)
e5(TSE5,TipoE5,ModoE5,_,EtqhE5,EtqE5,CodE5) -->
/*
	Mem.etqh = E5.etqh
*/
	mem(TSE5,PropsMem,EtqhE5,EtqE5,CodE5),
	{
	/*
		TODO: E5.tipo = Mem.props.t
		E5.modo = "var"
		
		E5.etq = Mem.etq
		E5.cod = Mem.cod
	*/
		ModoE5=var,
		
		dameAtrib(PropsMem,t,TipoE5)
	}.
%E5(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)
e5(TSE5,TipoE5,ModoE5,ParhE5,EtqhE5,EtqE5,CodE5) -->
/*
	E5Otro.ts = E5.ts
	E5.tipo = E5Otro.tipo
	E5.modo = E5Otro.modo
	
	E5Otro.parh = E5.parh
	E5Otro.etqh = E5.etqh
*/
	e5Otro(TSE5,TipoE5,ModoE5,ParhE5,EtqhE5,EtqE5,CodE5).
/*
	E5.etq = E5Otro.etq
	E5.cod = E5Otro.cod
*/

%E5Otro(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)	
e5Otro(TSE5Otro,TipoE5Otro,ModoE5Otro,ParhE5Otro,EtqhE5Otro,EtqE5Otro,CodE5Otro) -->
/*
	Op5cast.etqh = E5Otro.etqh
*/
	op5cast(OpOp5Cast,EtqhE5Otro,EtqOp5Cast,CodOp5Cast),
/*
	E6.ts = E5Otro.ts	
	
	E6.parh = E5Otro.parh
	E6.etqh = Op5cast.etq,
*/	
	e6(TSE5Otro,TipoE6,_,ParhE5Otro,EtqOp5Cast,EtqE5Otro,CodE6),
	{
	/*
		E5Otro.tipo = tipoDeU(Op5cast.op, E6.tipo)
		E5Otro.modo = "val"
		
		E5Otro.etq = E5.etq
		E5Otro.cod = E6.cod || Op5cast.cod
	*/
		tipoDeU(OpOp5Cast,TipoE6,TipoE5Otro),
		ModoE5Otro=val,
		
		agrega([CodE6,CodOp5Cast],CodE5Otro)
	}.
%E5Otro(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)	
e5Otro(TSE5Otro,TipoE5Otro,ModoE5Otro,ParhE5Otro,EtqhE5Otro,EtqE5Otro,CodE5Otro) -->
/*
	Op5u.etqh = E5otro.etqh
*/
	op5u(OpOp5u,EtqhE5Otro,EtqOp5U,CodOp5U),
/*
	E5.ts = E5Otro.ts
	
	E5.parh = E5Otro.parh
	E5.etqh = Op5u.etq
*/
	e5(TSE5Otro,TipoE5,_,ParhE5Otro,EtqOp5U,EtqE5Otro,CodE5),
	{
	/*
		E5Otro.tipo = tipoDeU(Op5u.op, E5.tipo)
		E5Otro.modo = "val"	
		
		E5Otro.etq = E5.etq
		E5Otro.cod = E5.cod || Op5u.cod
	*/
		tipoDeU(OpOp5u,TipoE5,TipoE5Otro),
		ModoE5Otro=val,
		
		agrega([CodE5,CodOp5U],CodE5Otro)
	}.
%E5Otro(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)	
e5Otro(TSE5Otro,TipoE5Otro,ModoE5Otro,ParhE5Otro,EtqhE5Otro,EtqE5Otro,CodE5Otro) --> 
/*
	E6Otro.ts = E5Otro.ts
	
	E6Otro.parh = E5Otro.parh
	E6Otro.etqh = E5Otro.etqh
*/
	e6Otro(TSE5Otro,TipoE5Otro,ModoE5Otro,ParhE5Otro,EtqhE5Otro,EtqE5Otro,CodE5Otro).
/*
	E5Otro.tipo = E6Otro.tipo
	E5Otro.modo = E6Otro.modo
	
	E5Otro.etq = E6Otro.etq
	E5Otro.cod = E6Otro.cod
*/

%E6(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)	
e6(_,TipoE6,ModoE6,_,EtqhE6,EtqE6,CodE6) --> 
	% null
	[(nulo,_,_)],
	{
	/*
		E6.tipo = "puntero"
		E6.modo = "val"
		
		E6.cod = "Apila_dir (-1)"
		E6.etq = E6.etqh + 1			
	*/
		TipoE6=puntero,
		ModoE6=puntero,
		
		CodE6 = [apila_dir(-1)],
		EtqE6 is EtqhE6 + 1
	}.

%E6(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)
e6(TSE6,TipoE6,ModoE6,_,EtqhE6,EtqE6,CodE6) --> 
/*
	IFun.ts = E6.ts

	IFun.etqh = E6.etqh
*/
	iFun(TSE6,IDFun,ErrFun,EtqhE6,EtqE6,CodE6),
	{
	/*
		E6.modo = "val"
		E6.tipo = if(IFun.err, Error, E6.ts[IFun.id].props.ret)
	
		E6.cod = IFun.cod
		E6.etq = IFun.etq
	*/
		ModoE6=val,
		(igual(ErrFun,true,true) -> 	TipoE6=error,
									(buscaEnTabla(TSE6,IDFun,E),dameAtrib(E,props,Props),dameAtrib(Props,ret,TipoE6)))
	}.
%E6(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)	
e6(TSE6,TipoE6,ModoE6,ParhE6,EtqhE6,EtqE6,CodE6) --> 
/*
	E6Otro.ts = E6.ts

	E6Otro.parh = E6.parh
	E6Otro.etqh = E6.etqh
*/
	e6Otro(TSE6,TipoE6,ModoE6,ParhE6,EtqhE6,EtqE6,CodE6).
/*
	E6.tipo = E6Otro.tipo
	E6.modo = E6Otro.modo

	E6.etq = E6Otro.etq
	E6.cod = E6Otro.cod
*/

%E6Otro(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)	
e6Otro(TSE6Otro,TipoE6Otro,ModoE6Otro,ParhE6Otro,EtqhE6Otro,EtqE6Otro,CodE6Otro) --> 
	% \( E0 \)
	[(pap,_,_)],
/*
	E0.ts = E6Otro.ts

	E0.parh = E6Otro.parh
	E0.etqh = E6Otro.etqh
*/
	e0(TSE6Otro,TipoE6Otro,ModoE6Otro,ParhE6Otro,EtqhE6Otro,EtqE6Otro,CodE6Otro),
	[(pcierre,_,_)].
/*
	E6Otro.modo = E0.modo
	E6Otro.tipo = E0.tipo
	
	E6Otro.etq = E0.etq
	E6Otro.cod = E0.cod
*/

%E6Otro(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)	
e6Otro(_,TipoE6Otro,ModoE6Otro,_,EtqhE6Otro,EtqE6Otro,CodE6Otro) --> 
	%Reales
	real(LexReal,_,_),
	{
	/*
		E6Otro.tipo = Real
		E6Otro.modo = "val"
	
		E6.cod = "ApilaR (Reales.lex)"
		E6.etq = E6.etqh + 1
	*/
		TipoE6Otro=real,
		ModoE6Otro=val,
		
		CodE6Otro=[apilaR(LexReal)],
		EtqE6Otro is EtqhE6Otro + 1
	}.
%E6Otro(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)	
e6Otro(_,TipoE6Otro,ModoE6Otro,_,EtqhE6Otro,EtqE6Otro,CodE6Otro) --> 
	%EntPos
	entpos(LexEntPos,_,_),
	{
	/*
		E6Otro.tipo = Int
		E6Otro.modo = "val"
		
		E6.cod = "ApilaI (EntPos.lex)"
		E6.etq = E6.etqh + 1
	*/
		TipoE6Otro=int,
		ModoE6Otro=val,
		
		CodE6Otro=[apilaI(LexEntPos)],
		EtqE6Otro is EtqhE6Otro + 1
	}.

%E6(+TS,-Tipo,-Modo,+Parh,+Etqh,-Etq,-Cod)		
e6(TSE6,TipoE6,ModoE6,ParhE6,EtqhE6,EtqE6,CodE6) --> 
/*
	Mem.ts = E6.ts

	Mem.etqh = E6.etqh
*/
	mem(TSE6,PropsMem,EtqhE6,EtqMem,CodMem),
	{
	/*	
		TODO: E6.tipo = Mem.props.t
		E6.modo = "var"
		
		E6.cod = if ((compatible(Mem.props,<t:int>,E6.tsh) v 
					 compatible(Mem.props,<t:real>,E6.tsh)) && 
					 !E6.parh,
						Mem.cod || "apila_ind",
						Mem.cod)
		E6.etq = if ((compatible(Mem.tipo,<t:int>,E6.tsh) v 
					 compatible(Mem.tipo,<t:real>,E6.tsh)) && 
					 !E6.parh,
						Mem.etq + 1,
					Mem.etq
	*/
		ModoE6=var,
		compatible(TSE6,PropsMem,(t,int),T1),
		compatible(TSE6,PropsMem,(t,real),T2),
		or([T1,T2],O1),
		not(ParhE6,A1),
		dameAtrib(PropsMem,t,TipoE6),
		(and([O1,A1],true)-> (agrega([CodMem,[apila_ind]],CodE6),
							  EtqE6 is EtqMem+1)
							;
							 (agrega([CodMem],CodE6),
							  EtqE6 is EtqMem)
		)
	}.

%IFun(+TS,-ID,-Error,+Etqh,-Etq,-Cod)	
iFun(TSFun,IDFun,ErrFun,EtqhIFun,EtqIFun,CodIFun) --> 
	id(IDFun,_,_), 
	% \( AParams \)
	[(pap,_,_)],
	{
	/*
		AParams.ts = IFun.ts
		AParams.FParamsh = IFun.tsh[ID.lex].props.params
		
		AParams.etqh = IFun.etqh + LongApilaRet
	*/

		buscaEnTabla(TSFun,IDFun,BloqueID),
		dameAtrib(BloqueID,props,Props),
		dameAtrib(Props,params,FParamshAParams),
	
		longApilaRet(LongApilaRet),
		EtqhAParams is EtqhIFun + LongApilaRet
	},
	aParams(TSFun,FParamshAParams,ErrAParams,EtqhAParams,EtqAParams,CodAParams),
	[(pcierre,_,_)],
	{
	/*
		IFun.err = !existeID(IFun.tsh, ID.lex) v IFun.tsh[ID.lex].clase!= "fun" v AParams.err
		IFun.id = ID.lex
		
		IFun.cod = Apila_ret(IFun.etq) || AParams.cod || Ir_a(IFun.tsh[ID.lex].props.inicio)
		IFun.etq = AParams.etq + 1
	*/
		buscaEnTabla(TSFun,IDFun,X1),
		dameAtrib(X1,id,IDFun1),
		igual(IDFun,IDFun1,Eq),
		dameAtrib(X1,clase,ClaseFun),
		igual(ClaseFun,fun,EqClase),
		or([ErrAParams,Eq,EqClase],ErrFun),
	
		buscaEnTabla(TSFun,IDFun,X1),
		dameAtrib(X1,props,Props),
		dameAtrib(Props,inicio,InicioProps),
		agrega([[apilaRet(EtqIFun)],CodAParams,[ir_a(InicioProps)]],CodIFun),
		EtqIFun is EtqAParams + 1
	}.
	
%AParams(+TS,+FParamsh,-Error,+Etqh,-Etq,-Cod)		
aParams(TSAParams,FParamshAParams,ErrAParams,EtqhAParams,EtqAParams,CodAParams) --> 
	{
	/*
		LAParams.FParamsh = AParams.FParamsh
		LAParams.tsh = AParams.tsh
	
		LAParams.etqh = AParams.etqh + LongInicioPaso()	
	*/
		longInicioPaso(LongInicioPaso),
		EtqhLAParams is EtqhAParams + LongInicioPaso
	},
	lAParams(TSAParams,FParamshAParams,NumParamsLAParams,ErrAParams,EtqhLAParams,EtqLAParams,CodLAParams),
	{
	/*	TODO
		AParams.err = LAParams.err v (|AParams.FParamsh| != LAParams.numParams)
		AParams.cod = Inicio-paso() || LAParams.cod || Fin-paso()
		AParams.etq = LAParams.etq + LongFinPaso()
	*/
	
	
		inicioPaso(InicioPaso),
		funPaso(FinPaso),
		agrega([InicioPaso,CodLAParams,FinPaso],CodAParams),
		longFinPaso(LongFinPaso),
		EtqAParams is EtqLAParams + LongFinPaso
	}.

%AParams(+TS,+FParamsh,-Error,+Etqh,-Etq,-Cod)		
aParams(_,FParamshAParams,ErrAParams,EtqhAParams,EtqhAParams,CodAParams) --> 
	% lambda
	[],
	{
	/*	TODO
		AParams.err = |AParams.FParamsh|>0
		AParams.etq = AParams.etqh
		AParams.cod = ""
	*/
		length(FParamshAParams,V),
		mayor(V,0,ErrAParams),
		CodAParams=[]
	}.

%lAParams(+TS,+FParamsh,-NumParams,-Error,+Etqh,-Etq,-Cod),
lAParams(TSLAParams,FParamshLAParams,NumParamsLAParams,ErrLAParams,EtqhLAParams,EtqLAParams,CodLAParams) -->
/*
	E0.ts = LAParams.ts
	
	TODO E0.parh = (LAParams.FParamsh[LAParams.numParams].modo == var)
	E0.etqh = LAParams.etqh
*/
	e0(TSLAParams,TipoE0,ModoE0,ParhE0,EtqhLAParams,EtqE0,CodE0),
/*
	RLAParams.ts = LAParams.ts
	RLAParams.FParamsh = LAParams.FParamsh

	RLAParams.etqh = E0.etq
	RLAParams.codh = Copia || E0.cod || pasoParametro(E0.modo,LAParams.FParamsh[1])
*/
	rLAParams(TSLAParams,FParamshLAParams,NumParamsRLAParams,ErrRLAParams,EtqE0,EtqRLAParams,CodhRLAParams,CodLAParams),
	{
	/*
		TODO
		LAParams.err = RLAParams.err v E0.err v LAParams.numParams > |LAParams.FParamsh| v
					  (LAparams.FParamsh[LAParams.numParams].modo = "var" && E0.modo == "val") v
					  !compatibles(LAParams.FParamsh[LAParams.numParams].tipo, E0.tipo, LAParams.tsh)			  
		LAParams.numParams = RLAParams.numParams + 1			  		
	
		LAParams.cod = RLAParams.cod
		TODO
		LAParams.etq = RLAParams.etq + LongPasoParametro(E0.modo,LAParams.FParamsh[LAParams.numParams]) + LongDireccionParFormal(LAParams.FParamsh[LAParams.numParams])
	*/
		NumParamsLAParams is NumParamsRLAParams + 1,
		
		EtqLAParams is EtqRLAParams + LongPasoParametro + LongDireccionParFormal
	}.
%RLAParams(+TS,+FParams,-NumParams,-Error,+Etqh,-Etq,-Cod)
rLAParams(TSRLAParams0,FParamshRLAParams0,NumParamsRLAParams0,ErrRLAParams0,EtqhRLAParams0,EtqRLAParams0,CodhRLAParams0,CodRLAParams0) --> 
	% , 
	[(coma,_,_)],
	{
	/*
		E0.ts = RLAParams(0).ts
		
		E0.parh = (RLAParams(0).FParamsh[RLAParams(0).numParams].modo == var)
		E0.etqh = RLAParams(0).etqh
	*/
	Modo=var, %TODO
	igual(Modo,var,ParhE0)
	},
	e0(TSRLAParams0,TipoE0,ModoE0,ParhE0,EtqhRLAParams0,EtqE0,CodE0),
	{
	/*
		RLAParams(1).ts = RLAParams(0).ts
		RLAParams(1).FParamsh = RLAParams(0).FParamsh

		RLAParams(1).etqh = E0.etq
		TODO
		RLAParams(1).codh = RLAParams(0).codh || Copia || 
						  DireccionParFormal(RLAParams(0).FParamsh[RLAParams(0).numParams]) || 
						  E0.cod || 
						  PasoParametro(E0.modo,RLAParams(0).FParamsh[LAParams(0).numParams])					  
	*/
		agrega([CodhRLAParams0,[copia],DireccionParFormal,CodE0,PasoParametro],CodhRLAParams1)
	},
	rLAParams(TSRLAParams0,FParamshRLAParams0,NumParamsRLAParams1,ErrRLAParams1,EtqE0,EtqRLAParams1,CodhRLAParams1,CodRLAParams0),
	{
	/*
		TODO
		RLAParams(0).err = RLAParams(1).err v E0.err v RLAParams(0).numParams > |RLAParams(0).FParamsh| v
					  (RLAparams(0).FParamsh[RLAParams(0).numParams].modo = "var" && E0.modo == "val") v
				     TODO !compatibles(RLAParams(0).FParamsh[RLAParams(0).numParams].tipo, E0.tipo, RLAParams(0).tsh)			  
		RLAParams(0).numParams = RLAParams(1).numParams + 1

		RLAParams(0).etq = RLAParams(1).etq + LongPasoParametro(E0.modo,RLAParams(0).FParamsh[RLAParams(0).numParams]) + LongDireccionParFormal(RLAParams(0).FParamsh[RLAParams(0).numParams])			  			 
	*/
		igual(TipoE0,[(t:error)],ErrE0),
			length(FParamshRLAParams0,Long),
			mayor(NumParamsRLAParams0,Long,Mayor),
		igual(ModoE0,val,Modo),
			
		or([ErrRLAParams1,ErrE0,Mayor,Modo],ErrRLAParams0),
		NumParamsRLAParams0 is NumParamsRLAParams1 + 1,
		
		longPasoParametro(LongPasoParametro),
		longDireccionParFormal(LongDireccionParFormal),
		
		EtqRLAParams0 is EtqRLAParams1 + LongPasoParametro + LongDireccionParFormal
	}.
%RLAParams(+TS,+FParams,-NumParams,-Error,+Etqh,-Etq,-Cod)
rLAParams(_,_,NumParamsRLAParams,ErrRLAParams,EtqhRLAParams,EtqhRLAParams,CodhRLAParams,CodhRLAParams) --> 
	% lambda
	[],
	{
	/*
		RLAParams.err = False
		RLAParams.numParams = 0	  
	
		RLAParams.etq = RLAParams.etqh
		RLAParams.cod = RLAParams.codh
	*/
		NumParamsRLAParams is 0,
		ErrRLAParams = false
	}.


%op2(-Op,+Etqh,-Etq,-Cod)
op2(Op,Etqh,Etq,Cod) --> 
	% <
	[(menor,_,_)],
	{
	/*
		Op2.op = Menor

		Op2.cod = "Menor"
		Op2.etq = Op2.etqh + 1
	*/
		Op=menor,
		Cod=[menor],
		Etq is Etqh + 1
	}.
%op2(-Op,+Etqh,-Etq,-Cod)
op2(Op,Etqh,Etq,Cod) -->
	% >
	[(mayor,_,_)],
	{
	/*
		Op2.op = Mayor
	
		Op2.cod = "Mayor"
		Op2.etq = Op2.etqh + 1
	*/
		Op=mayor,
		Cod=[mayor],
		Etq is Etqh + 1
	}.
%op2(-Op,+Etqh,-Etq,-Cod)
op2(Op,Etqh,Etq,Cod) -->
	% <=
	[(menIg,_,_)],
	{
	/*
		Op2.op = MenIg
		
		Op2.cod = "MenIg"
		Op2.etq = Op2.etqh + 1
	
	
	*/
		Op=menIg,
		Cod=[menIg],
		Etq is Etqh+1
	}.
%op2(-Op,+Etqh,-Etq,-Cod)	
op2(Op,Etqh,Etq,Cod) --> 
	% >=
	[(mayIg,_,_)],
	{
	/*
		Op2.op = MayIg
	
		Op2.cod = "MayIg"
		Op2.etq = Op2.etqh + 1
	*/
		Op=mayIg,
		Cod=[mayIg],
		Etq is Etqh+1
	}.
%op2(-Op,+Etqh,-Etq,-Cod)
op2(Op,Etqh,Etq,Cod) --> 
	% ==
	[(igual,_,_)],
	{
	/*
		Op2.op = Igual
		
		Op2.cod = "Igual"
		Op2.etq = Op2.etqh + 1
	*/
		Op=igual,
		Cod=[igual],
		Etq is Etqh+1
	}.
%op2(-Op,+Etqh,-Etq,-Cod)
op2(Op,Etqh,Etq,Cod) --> 
	% != 
	[(distinto,_,_)],
	{
	/*
		Op2.op = Distinto
		
		Op2.cod = "Distinto"
		Op2.etq = Op2.etqh + 1
	*/
		Op=distinto,
		Cod=[distinto],
		Etq is Etqh+1
	}.
%op3(-Op,+Etqh,-Etq,-Cod)
op3(Op,Etqh,Etq,Cod) --> 
	% ||
	[(opo,_,_)],
	{
	/*
		Op3.op = LogicO
		
		Op3.cod = "LogicO"
		Op3.etq = Op3.etqh + 1
	*/
		Op=opo,
		Cod=[opo],
		Etq is Etqh+1
	}.
%op3(-Op,+Etqh,-Etq,-Cod)
op3(Op,Etqh,Etq,Cod) -->
	% +
	[(mas,_,_)],
	{
	/*
		Op3.op = Suma
	
		Op3.cod = "Suma"
		Op3.etq = Op3.etqh + 1
	*/
		Op=mas,
		Cod=[mas],
		Etq is Etqh+1
	}.	
%op3(-Op,+Etqh,-Etq,-Cod)
op3(Op,Etqh,Etq,Cod) --> 
	% -
	[(menos,_,_)],
	{
	/*
		Op3.op = Resta
		
		Op3.cod = "Resta"
		Op3.etq = Op3.etqh + 1
	*/
		Op=menos,
		Cod=[menos],
		Etq is Etqh+1
	}.
%op4(-Op,+Etqh,-Etq,-Cod)
op4(Op,Etqh,Etq,Cod) -->
	% *
	[(por,_,_)],
	{
	/*
		Op4.op = Multiplicacion
		
		Op4.cod = "Mult"
		Op4.etq = Op4.etqh + 1
	*/
		Op=por,
		Cod=[por],
		Etq is Etqh+1
	}.
%op4(-Op,+Etqh,-Etq,-Cod)
op4(Op,Etqh,Etq,Cod) -->
	% /
	[(div,_,_)],
	{
	/*
		Op4.op = Division
		
		Op4.cod = "Div"
		Op4.etq = Op4.etqh + 1
	*/
		Op=div,
		Cod=[div],
		Etq is Etqh+1
	}.
%op4(-Op,+Etqh,-Etq,-Cod)
op4(Op,Etqh,Etq,Cod) --> 
	% %
	[(mod,_,_)],
	{
	/*
		Op4.op = Modulo
	
		Op4.cod = "Mod"
		Op4.etq = Op4.etqh + 1	
	*/
		Op=mod,
		Cod=[mod],
		Etq is Etqh+1
	}.
%op4(-Op,+Etqh,-Etq,-Cod)
op4(Op,Etqh,Etq,Cod) --> 
	% &&
	[(opy,_,_)],
	{
	/*
		Op4.op = LogicY
	
		Op4.cod = "LogicY"
		Op4.etq = Op4.etqh + 1
	*/
		Op=opy,
		Cod=[opy],
		Etq is Etqh+1
	}.
%op5U(-Op,+Etqh,-Etq,-Cod)
op5u(Op,Etqh,Etq,Cod) --> 
	% -
	[(menos,_,_)],
	{
	/*	
		Op5u.op = CambioDeSigno
	
		Op5u.cod = "CambioDeSigno"
		Op5u.etq = Op5u.etqh + 1	
	*/
		Op=menos,
		Cod=menos,
		Etq is Etqh+1
	}.
%op5U(-Op,+Etqh,-Etq,-Cod)
op5u(Op,Etqh,Etq,Cod) --> 
	% !
	[(neg,_,_)],
	{
	/*
		Op5u.op = LogicNo
	
		Op5u.cod = "LogicNo"
		Op5u.etq = Op5u.etqh + 1
	*/
		Op=neg,
		Cod=neg,
		Etq is Etqh+1
	}.
%op5Cast(-Op,+Etqh,-Etq,-Cod)	
op5cast(Op,Etqh,Etq,Cod) --> 
	% castInt
	[(castint,_,_)],
	{
	/*
		Op5cast.op = ConvAInt
	
		Op5cast.cod = "ConvAInt"
		Op5cast.etq = Op5cast.etqh + 1
	*/
		Op=convInt,
		Cod=[convInt],
		Etq is Etqh+1
	}.
%op5Cast(-Op,+Etqh,-Etq,-Cod)
op5cast(Op,Etqh,Etq,Cod) --> 
	% castReal
	[(castreal,_,_)],
	{
	/*
		Op5cast.op = ConvAReal		
	
		Op5cast.cod = "ConvAReal"
		Op5cast.etq = Op5cast.etqh + 1
	*/
		Op=convReal,
		Cod=[convReal],
		Etq is Etqh+1
	}.

	
	
	
	
	
	
	
	
	
	
	
	
	
	
/* Lista de palabras reservadas */
reservada('DO',hacer).
reservada('IF',iniIf).
reservada('FI',finIf).
reservada('ELSE',relse).
reservada('ELSIF',relsif).
reservada('THEN',then).
reservada('END',fin).
reservada('NULL',nulo).
reservada('WHILE',iniWhile).
reservada('ENDWHILE',finWhile).
reservada('POINTER',puntero).
reservada('FUN',iniFun).
reservada('TIPO',tipo).
reservada('ARRAY',array).
reservada('REC',iniRec).
reservada('ENDREC',finRec).
reservada('OF',de).
reservada('RETURN',retorno).
reservada('ALLOC',reservaMem).
reservada('FREE',liberaMem).
reservada('IN',entrada).
reservada('OUT',salida).
reservada('INT',tInt).
reservada('REAL',tReal).

/* Minusculas : ASCII --> a=97, z=122 */
minus(X):-name(X,[Y]),between(97,122,Y).

/* Mayuscula : ASCII --> A=64, Z=90 */
mayus(X):-name(X,[Y]),between(65,90,Y).


/* Letra */
letra(X):-minus(X).
letra(X):-mayus(X).

/* Numero positivo : ASCII --> 1=49, 9=56*/
numPos(X):-name(X,[Y]),between(49,56,Y).

/* Numero */
exponente('e').
exponente('E').
cero('0').
num(X):-numPos(X).
num(X):- cero(X).

/* Pasa el string a lista de caracteres. Para luego devolver a string usar name (ver help(name)). */
aLista([],[]).
aLista([X|Xs],Ys):-name(X,Y),aLista(Xs,Zs),append(Y,Zs,Ys).

/* Funcion de igualdad */
equal(Char,Char).

/* -------------------------------------------------------------------------------------------------------
        Procesamiento texto
   ------------------------------------------------------------------------------------------------------- */
procesa(File, Xs) :-
    open(File, read, In),
    get_char(In, Char),
    listaCaract(Char, In, Xs),
    close(In).

listaCaract(end_of_file, _, []) :- !.
listaCaract(Char,In,[Char|Xs]):-
        get_char(In, Char1),
    listaCaract(Char1,In, Xs).

/* -------------------------------------------------------------------------------------------------------
        Procesamiento lexico. 
   ------------------------------------------------------------------------------------------------------- */

tokenizer(ListaSimbolos,ListaTokens,_,_):-
        init(ListaTokens,_,_,ListaSimbolos,[]).


init(Tokens,Le,Pe) --> {L is 1, P is 1},inicio(Tokens,Le,Pe,L,P).

/* Blancos */
inicio(Tokens,Le,Pe,L,P) -->    [' '],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).
inicio(Tokens,Le,Pe,L,P) -->    ['\t'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).
inicio(Tokens,Le,Pe,L,_) -->    ['\n'],!,{L1 is L + 1, P1 is  1},inicio(Tokens,Le,Pe,L1,P1).    
inicio(Tokens,Le,Pe,L,P) -->    ['\r'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).          

/* Identificador */
inicio(Tokens,Le,Pe,L,P,[Car|RCs],Rs):- letra(Car),!,name(Car,Str),append([],Str,Str1),P1 is P + 1,ident(Tokens,Le,Pe,L,P1,Str1,RCs,Rs).

/* Numero entero */
inicio(Tokens,Le,Pe,L,P,[Car|RCs],Rs):- numPos(Car),!,name(Car,Str),append([],Str,Str1),P1 is P + 1,numeroPos(Tokens,Le,Pe,L,P1,Str1,RCs,Rs).
inicio(Tokens,Le,Pe,L,P,[Car|RCs],Rs):- cero(Car),!,name(Car,Str),append([],Str,Str1),P1 is P + 1,numeroCero(Tokens,Le,Pe,L,P1,Str1,RCs,Rs).

/* Punto y coma */
inicio([(pyc,L,P)|Tokens],Le,Pe,L,P) --> [';'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).

/* Punto y coma */
inicio([(coma,L,P)|Tokens],Le,Pe,L,P) --> [','],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).

/* Parentesis y castings */
inicio(Tokens,Le,Pe,L,P) --> ['('],!,{P1 is P + 1},casting(Tokens,Le,Pe,L,P1).
inicio([(pcierre,L,P)|Tokens],Le,Pe,L,P) --> [')'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).

/* Corchetes */
inicio([(cap,L,P)|Tokens],Le,Pe,L,P) --> ['['],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).
inicio([(ccierre,L,P)|Tokens],Le,Pe,L,P) --> [']'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).

/* Sombrero de puntero ( ^ ) */
inicio([(sombrero,L,P)|Tokens],Le,Pe,L,P) --> ['^'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).

/* Punto (\.) */
inicio([(punto,L,P)|Tokens],Le,Pe,L,P) --> ['.'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).

/* Operacion || */
inicio(Tokens,Le,Pe,L,P) --> ['|'],!,{P1 is P + 1},o(Tokens,Le,Pe,L,P1).

/* Comentario */
inicio(Tokens,Le,Pe,L,P) --> ['@'],!,{P1 is P + 1},comentario(Tokens,Le,Pe,L,P1).                                                                       

/* Operacion % */
inicio([(mod,L,P)|Tokens],Le,Pe,L,P) --> ['%'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).                                                                     

% Operacion /
inicio([(div,L,P)|Tokens],Le,Pe,L,P) --> ['/'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).

/* Operacion * */
inicio([(por,L,P)|Tokens],Le,Pe,L,P) --> ['*'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).

/* Operacion - */
inicio([(menos,L,P)|Tokens],Le,Pe,L,P) --> ['-'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).                                                                   

/* Operacion + */
inicio([(mas,L,P)|Tokens],Le,Pe,L,P) --> ['+'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).

/* Operacion && */
inicio(Tokens,Le,Pe,L,P) --> ['&'],!,{P1 is P + 1},amp(Tokens,Le,Pe,L,P1).                                                                                                                      

/* Operacion >, >= */
inicio(Tokens,Le,Pe,L,P) --> ['>'],!,{P1 is P + 1},mayor(Tokens,Le,Pe,L,P1).

/* Operacion <, <= */
inicio(Tokens,Le,Pe,L,P) --> ['<'],!,{P1 is P + 1},menor(Tokens,Le,Pe,L,P1).

/* Operacion =, == */
inicio(Tokens,Le,Pe,L,P) --> ['='],!,{P1 is P + 1},igual(Tokens,Le,Pe,L,P1).

/* Operacion !, != */
inicio(Tokens,Le,Pe,L,P) --> ['!'],!,{P1 is P + 1},distinto(Tokens,Le,Pe,L,P1).

/* En caso de error */
inicio([],L,P,L,P) --> []. 

/* Operacion =, == */
igual([(igual,L,P)|Tokens],Le,Pe,L,P) --> ['='],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).                                                                                                                                                                                                                    
igual([(asig,L,P)|Tokens],Le,Pe,L,P) --> [],!,inicio(Tokens,Le,Pe,L,P).

/* Operacion !, != */
distinto([(distinto,L,P)|Tokens],Le,Pe,L,P) --> ['='],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).
distinto([(neg,L,P)|Tokens],Le,Pe,L,P) --> [],!,inicio(Tokens,Le,Pe,L,P).

/* Operacion && */
amp([(opy,L,P)|Tokens],Le,Pe,L,P) --> ['&'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).                                                                                                                                                                                                                        
amp([(amp,L,P)|Tokens],Le,Pe,L,P) --> [],!,inicio(Tokens,Le,Pe,L,P).


/* Operacion || */
o([(opo,L,P)|Tokens],Le,Pe,L,P) --> ['|'],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).                                                                                                                                          
%o([_],Le,Pe,Le,Pe) --> [].

/* Comentario */
comentario(Tokens,Le,Pe,L,_) -->        ['\n'],!,{L1 is L + 1, P1 is 1},inicio(Tokens,Le,Pe,L1,P1).
comentario(Tokens,Le,Pe,L,P) -->        [_],!,{P1 is P+1},comentario(Tokens,Le,Pe,L,P1).
comentario([],L,P,L,P) -->      [],!.

/* Operacion >, >= */
mayor([(mayIg,L,P)|Tokens],Le,Pe,L,P) --> ['='],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).                                                                                                                                                                                                                    
mayor([(mayor,L,P)|Tokens],Le,Pe,L,P) --> [],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).

/* Operacion <, <= */
menor([(menIg,L,P)|Tokens],Le,Pe,L,P) --> ['='],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).                                                                                                                                                                                                                    
menor([(menor,L,P)|Tokens],Le,Pe,L,P) --> [],!,{P1 is P + 1},inicio(Tokens,Le,Pe,L,P1).

/* Casting */
casting([(castint,L,P)|Tokens],Le,Pe,L,P) --> ['i','n','t',')'],!,{P1 is P + 4},inicio(Tokens,Le,Pe,L,P1).                                                                                                                                                                                                                    
casting([(castreal,L,P)|Tokens],Le,Pe,L,P) --> ['r','e','a','l',')'],!,{P1 is P + 5},inicio(Tokens,Le,Pe,L,P1).
casting([(pap,L,P)|Tokens],Le,Pe,L,P) --> [],!,inicio(Tokens,Le,Pe,L,P).

/* Identificador */
ident(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- letra(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,ident(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
ident(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- num(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,ident(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
ident([(Tok,L,P)|Tokens],Le,Pe,L,P,Str,RCs,Rs):- name(Cad,Str),upcase_atom(Cad,Cad1),reservada(Cad1,Tok),!,inicio(Tokens,Le,Pe,L,P,RCs,Rs).
ident([(id(Cad1),L,P)|Tokens],Le,Pe,L,P,Str,RCs,Rs):- name(Cad,Str),upcase_atom(Cad,Cad1),inicio(Tokens,Le,Pe,L,P,RCs,Rs).

/* Numero positivo */
numeroPos(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- num(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroPos(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroPos(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- exponente(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal2(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroPos(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- equal(Car,'.'),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal1(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroPos(Tokens,Le,Pe,L,P,_,[Car|RCs],_):- letra(Car),!,write('Numero no valido\n'), write(linea-L),nl,write(posicion-P),nl,asserta(errorLexico),inicio(Tokens,Le,Pe,L,P,RCs,Rs).
numeroPos([(int(Cad),L,P)|Tokens],Le,Pe,L,P,Str,RCs,Rs):- name(Cad,Str),inicio(Tokens,Le,Pe,L,P,RCs,Rs).

/* Numero cero. Puede desembocar en numero real */
numeroCero(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- equal(Car,'.'),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal1(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroCero([],L,P,L,P,_,[Car|RCs],_):- letra(Car),!,write('Numero no valido\n'), write(linea-L),nl,write(posicion-P),nl,assert(errorLexico),inicio(_,_,_,L,P,RCs,_).
numeroCero([],L,P,L,P,_,[Car|RCs],_):- numPos(Car),!,write('Numero no valido\n'), write(linea-L),nl,write(posicion-P),nl,assert(errorLexico),inicio(_,_,_,L,P,RCs,_).
numeroCero([(int(Cad),L,P)|Tokens],Le,Pe,L,P,Str,RCs,Rs):- name(Cad,Str),inicio(Tokens,Le,Pe,L,P,RCs,Rs).

/* Numero real1: Sin exponente, pero el numero aun no es valido (p.e.: 1. 1.000 */
numeroReal1(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- cero(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal1(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroReal1(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- numPos(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal1a(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroReal1([],L,P,L,P,_,[_|RCs],_):- !,write('Numero no valido\n'), write(linea-L),nl,write(posicion-P),nl,assert(errorLexico),inicio(_,_,_,L,P,RCs,_).

/* Numero real1a: Sin exponente, y el numero no finaliza en 0 (es valido)*/
numeroReal1a(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- exponente(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal2(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroReal1a(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- cero(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal1(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroReal1a(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- numPos(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal1a(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroReal1a([],L,P,L,P,_,[Car|RCs],_):- letra(Car),!,write('Numero no valido\n'), write(linea-L),nl,write(posicion-P),nl,assert(errorLexico),inicio(_,_,_,L,P,RCs,_).
numeroReal1a([(real(Cad),L,P)|Tokens],Le,Pe,L,P,Str,RCs,Rs):- name(Cad,Str),inicio(Tokens,Le,Pe,L,P,RCs,Rs).

/* Numero real2: Con exponente, pero aun no valido (p.e. 1e 1.5e*/
numeroReal2(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- numPos(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal2a(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroReal2(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- equal(Car,'-'),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal2b(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroReal2([(real(Cad),L,P)|Tokens],Le,Pe,L,P,Str,[Car|RCs],Rs):- cero(Car),!,name(Car,Str1),append(Str,Str1,Str2),name(Cad,Str2),P1 is P + 1,inicio(Tokens,Le,Pe,L,P1,RCs,Rs).
numeroReal2([],L,P,L,P,_,[_|RCs],_):- !,write('Numero no valido\n'), write(linea-L),nl,write(posicion-P),nl,assert(errorLexico),inicio(_,_,_,L,P,RCs,_).

/* Numero real2a: Con exponente y valido (p.e. 1e6 1.5e-700*/
numeroReal2a(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- num(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal2a(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroReal2a([],L,P,L,P,_,[Car|RCs],_):- letra(Car),!,write('Numero no valido\n'), write(linea-L),nl,write(posicion-P),nl,assert(errorLexico),inicio(_,_,_,L,P,RCs,_).
numeroReal2a([(real(Cad),L,P)|Tokens],Le,Pe,L,P,Str,RCs,Rs):- name(Cad,Str),inicio(Tokens,Le,Pe,L,P,RCs,Rs).

/* Numero real2b: Con exponente negativo y no valido (p.e. 1.5e-*/
numeroReal2b(Tokens,Le,Pe,L,P,Str,[Car|RCs],Rs):- numPos(Car),!,name(Car,Str1),append(Str,Str1,Str2),P1 is P + 1,numeroReal2a(Tokens,Le,Pe,L,P1,Str2,RCs,Rs).
numeroReal2b([(real(Cad),L,P)|Tokens],Le,Pe,L,P,Str,[Car|RCs],Rs):- cero(Car),!,name(Car,Str1),append(Str,Str1,Str2),name(Cad,Str2),P1 is P + 1,inicio(Tokens,Le,Pe,L,P1,RCs,Rs). 


/* -------------------------------------------------------------------------------------------------------
        Tipo de las operaciones
   -------------------------------------------------------------------------------------------------------      */
%tipoDe(+tipo,+operacion,-tipoResultado)
%tipoDe(+tipo1,+tipo2,+operacion,-tipoResultado)
tipoDe(error,_,error):-!.                       /* Para poder subir el error hasta la raiz */
tipoDe(error,_,_,error):-!.
tipoDe(_,error,_,error):-!.
tipoDe(int,entrada,int):-!.
tipoDe(real,entrada,real):-!.
tipoDe(int,salida,int):-!.
tipoDe(real,salida,real):-!.
tipoDe(int,no,int):-!.
tipoDe(Tipo,menos,Tipo).
tipoDe(_,castInt,int):-!.
tipoDe(_,castReal,int):-!.
tipoDe(_,_,menor,int).
tipoDe(_,_,menIg,int).
tipoDe(_,_,mayor,int).
tipoDe(_,_,mayIg,int).
tipoDe(_,_,igual,int).
tipoDe(_,_,distinto,int).
tipoDe(Int,Int,mas,int):-Int = int.
tipoDe(Int,Int,menos,int):-Int = int.
tipoDe(Int,Int,por,int):-Int = int.
tipoDe(Int,Int,div,int):-Int = int.
tipoDe(Real,Real,mas,real):-Real = real.
tipoDe(Real,Real,menos,real):-Real = real.
tipoDe(Real,Real,por,real):-Real = real.
tipoDe(Real,Real,div,real):-Real = real.
tipoDe(_,_,mas,real).
tipoDe(_,_,menos,real).
tipoDe(_,_,por,real).
tipoDe(_,_,div,real).
tipoDe(int,int,or,int):-!.
tipoDe(int,int,and,int):-!.
tipoDe(int,int,mod,int):-!.
tipoDe(int,int,asig,int):-!.
tipoDe(real,_,asig,real).

%chequeaTipo(+Tipo1,+Tipo2,+Linea Token 2,+Pos Token 2,+operacion,-TipoResultado,-Error)
%chequeaTipo(+Tipo,+Linea Token,+Pos Token,+operacion,-TipoResultado,-Error)
chequeaTipo(Tipo1,Tipo2,Linea,Pos,Operacion,error,Error):-
        \+ tipoDe(Tipo1,Tipo2,Operacion,_),
        Error = ['Error de tipos en coordenadas:',linea:Linea,posicion:Pos].
chequeaTipo(Tipo1,Tipo2,_,_,Operacion,TipoResultado,[]):-   
        tipoDe(Tipo1,Tipo2,Operacion,TipoResultado).
        
chequeaTipo(Tipo,Linea,Pos,Operacion,error,Error):-
        \+ tipoDe(Tipo,Operacion,_),
        Error = ['Error de tipo en coordenadas:\n',linea:Linea,'\n',posicion:Pos].
chequeaTipo(Tipo,_,_,Operacion,TipoResultado,[]):-	tipoDe(Tipo,Operacion,TipoResultado).   


compilador(Fich):-retractall(errorLexico),procesa(Fich,X),tokenizer(X,LT,_,_),!,continua(LT).
continua(_):-errorLexico,abort.
continua(LT):-sintactico(LT).

sintactico(Lt):-prog(_,C,Lt,[]),escribe(C),!.

escribe(Xs):- tell('out.obj'),escribe1(Xs),told.
escribe1([]).
escribe1([C|Cs]):-write(C),nl,escribe(Cs).
